luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)

传送:https://www.luogu.org/problem/P3292

题意:

$n$座城市,$n-1$条路,每个城市有一个价值$a_i$。$q$个询问,每次询问城市$x$到城市$y$的路径上经过的城市的价值的最大异或和为多少。

数据范围:

$1<=n<=20000,q<=200000,a_i<=2^{60}$。

分析:

对于一次询问$x-->y$的路径上的答案,很明显就是$x-->lca(x,y)$的线性基并上$y-->lca(x,y)$的线性基,然后求最大异或和。

那么对于多个询问来说怎么考虑呢?

在一棵树上查询$lca$有两种做法:1)tarjan/dfs(离线);2)ST表+倍增(在线)。对于这个题很明显需要维护路径上的线性基,我们用第二种倍增的做法在求$lca$的同时,就可以维护线性基,然后查询答案。

用$f[i][j]$代表点$i$向上跳$2^j$布达到哪一个点。用$LB[i][j]$代表向上$2^j$步路径上的线性基。

然后求$lca$的过程中同时暴力合并线性基可以了鸭。(qaaaaq

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=2e4+10;
 5 struct node{
 6     int to,nxt;
 7 }edge[maxn*2];
 8 int head[maxn],f[maxn][20],deep[maxn],tot,N,n,q;
 9 ll a[maxn];
10 struct Linear_basis{
11     ll b[65];
12     bool insert(ll x){
13         for (int i=62;i>=0;i--){
14             if (x&(1ll<<i)){
15                 if (!b[i]){b[i]=x; break;}
16                 x^=b[i];
17             }
18         }
19         return x>0;  //是否可插入 true:可插入,false:不可插入
20     }
21     ll mx(){
22         ll res=0;
23         for (int i=62;i>=0;i--) res=max(res,res^b[i]);
24         return res;
25     }
26     void clear(){
27         memset(b,0,sizeof(b));
28     }
29 }LB[maxn][20],ans;
30 void add(int x,int y){
31     edge[++tot]={y,head[x]}; head[x]=tot;
32 }
33 void dfs(int x,int fa){
34     f[x][0]=fa; //倍增数组
35     LB[x][0].insert(a[x]);
36     for (int i=head[x];i!=-1;i=edge[i].nxt){
37         node tmp=edge[i];
38         if (tmp.to==fa) continue;
39         deep[tmp.to]=deep[x]+1;
40         dfs(tmp.to,x);
41     }
42 }
43 Linear_basis merge(Linear_basis p,Linear_basis q){
44     Linear_basis tmp=p;
45     for (int i=62;i>=0;i--){
46         if (q.b[i]) tmp.insert(q.b[i]);
47     }
48     return tmp;
49 }
50 void init(){
51     N=floor(log(1.0*n)/log(2.0));
52     deep[1]=0;
53     dfs(1,0);
54     for (int j=1;j<=N;j++){
55         for (int i=1;i<=n;i++){
56             f[i][j]=f[f[i][j-1]][j-1];
57             LB[i][j]=merge(LB[i][j-1],LB[f[i][j-1]][j-1]);
58         }
59     }
60 }
61 int _LCA(int x,int y){
62     if (deep[x]<deep[y]) swap(x,y);
63     for (int j=N;j>=0;j--)
64         if (deep[f[x][j]]>=deep[y]){
65             ans=merge(ans,LB[x][j]);
66             x=f[x][j];
67         }
68     if (x==y){
69         ans=merge(ans,LB[x][0]); return x;
70     }
71     for (int j=N;j>=0;j--){
72         if (f[x][j]!=f[y][j]){
73             ans=merge(ans,merge(LB[x][j],LB[y][j]));
74             x=f[x][j]; y=f[y][j];
75         }
76     }
77     Linear_basis tmp=merge(LB[x][0],LB[y][0]);
78     Linear_basis tmp2=merge(ans,LB[f[x][0]][0]);
79     ans=merge(tmp2,tmp);
80     return f[x][0]; //lca
81 }
82 int main(){
83     scanf("%d%d",&n,&q);
84     for (int i=1;i<=n;i++) scanf("%lld",&a[i]),head[i]=-1;
85     int x,y; tot=0;
86     for (int i=1;i<=n-1;i++){
87         scanf("%d%d",&x,&y);
88         add(x,y);add(y,x);
89     }
90     init();
91     while (q--){
92         scanf("%d%d",&x,&y);
93         ans.clear();
94         _LCA(x,y);
95         printf("%lld\n",ans.mx());
96     }
97     return 0;
98 }

原文地址:https://www.cnblogs.com/changer-qyz/p/11355642.html

时间: 2024-11-06 12:02:53

luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)的相关文章

bzoj4568: [Scoi2016]幸运数字 线性基 倍增

洛谷T了,mmp 还是bzoj时限良心,虽然三天两头爆炸 算是简单的题吧,构造出每个点logn个的线性基表 感觉线性基最nb的就是只有log个,所以可以做的很暴力 合并就是拆开再并 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct Bas 4 { 5 long long a[61]; 6 Bas() 7 { 8 for(int i=0;i<=60;i++) 9 a[i]=0; 10 } 11 void add(long

[SCOI2016]幸运数字 线性基

题面 题面 题解 题面意思非常明确:求树上一条链的最大异或和. 我们用倍增的思想. 将这条链分成2部分:x ---> lca , lca ---> y 分别求出这2个部分的线性基,然后合并,再求最大异或和. 所以我们现在只需要考虑如何在树上求一条无需拐弯的链的最大线性基. 考虑倍增. 我们预处理出f[i][j]表示从点i开始向上走\(2^j\)构成的链的线性基.至于只有点\(i\)一个点的线性基,我们可以在运算的时候特判一下处理. 暴力预处理后,我们就可以最多 合并3次 + 求LCA的复杂度

[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2131  Solved: 865[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x

【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)

4568: [Scoi2016]幸运数字 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国. 在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸

bzoj 4568: [Scoi2016]幸运数字

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 848  Solved: 336[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号

bzoj4568 [Scoi2016]幸运数字

Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国.在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸运是不能简单叠加的,这一点游览者也十分清楚.他们迷

BZOJ4568:[SCOI2016]幸运数字——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4568 https://www.luogu.org/problemnew/show/P3292 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征. 一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y

SCOI2016 幸运数字

传送门 如果只是一条路径的话,那就是非常简单的线性基. 不过要考虑多组询问-- 考虑到n比较小,我们可以模仿倍增LCA的方法,预处理倍增的线性基.在每次路径上跳的时候把线性基合并最后求解即可.具体的做法是,我们用\(p[i][x][j]\)表示在编号为x的点处,向上跳\(2^i\)步以内,线性基第j位的数.这个可以合并,比较好写的方法就是直接传两个数组进去合并. 之后就正常了.代码很短,不到100行.(我交了好多次因为忘记用longlong快读了--) #include<iostream> #

【BZOJ-4568】幸运数字 树链剖分 + 线性基合并

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 238  Solved: 113[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市