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 }