luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)
Posted changer-qyz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
以上是关于luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)的主要内容,如果未能解决你的问题,请参考以下文章