G70 前缀线性基+贪心法+LCA P3292 [SCOI2016] 幸运数字
视频链接:G70 前缀线性基+贪心法+LCA P3292 [SCOI2016] 幸运数字_哔哩哔哩_bilibili
G69 前缀线性基+贪心法 CF1100F Ivan and Burgers - 董晓 - 博客园 (cnblogs.com)
D09 倍增算法 P3379【模板】最近公共祖先(LCA) - 董晓 - 博客园 (cnblogs.com)
P3292 [SCOI2016] 幸运数字 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
// 前缀线性基+贪心法+LCA O(60*60*q) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define LL long long const int N=20005; int idx,head[N],to[N<<1],ne[N<<1]; void add(int x,int y){ to[++idx]=y;ne[idx]=head[x];head[x]=idx; } int n,q,x,y; int dep[N],fa[N][16]; int pos[N][61]; LL a[N],b[61],p[N][61]; void insert(int u,int f){ for(int i=0;i<=60;i++) //复制父版 p[u][i]=p[f][i],pos[u][i]=pos[f][i]; LL x=a[u]; int P=u; for(int i=60;i>=0;--i){ if((x>>i)&1){ if(!p[u][i]){ //不存在则加入 p[u][i]=x; pos[u][i]=P; break; } // 存在则先交换,后异或 if(dep[pos[u][i]]<dep[P]) swap(x,p[u][i]),swap(pos[u][i],P); x^=p[u][i]; } } } void dfs(int u,int f){ dep[u]=dep[f]+1; fa[u][0]=f; for(int i=1;i<=15;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; insert(u,f); //构造线性基 for(int i=head[u];i;i=ne[i]) if(to[i]!=f) dfs(to[i],u); } int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(int i=15;i>=0;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y) return x; for(int i=15;i>=0;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } LL query(int x,int y){ int lca=LCA(x,y); for(int i=60;i>=0;--i) //提取x~lca链的基 b[i]=dep[pos[x][i]]>=dep[lca]?p[x][i]:0; for(int i=60;i>=0;--i){ //暴力合并基 if(dep[pos[y][i]]>=dep[lca]){ LL x=p[y][i]; //提取y~lca链的基 for(int j=i;j>=0;--j){ if(x>>j&1){ if(!b[j]){b[j]=x;break;} x^=b[j]; } } } } LL ans=0; for(int i=60;i>=0;--i)ans=max(ans,ans^b[i]); return ans; } int main(){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=2;i<=n;i++){ scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(1,0); //树增 while(q--){ scanf("%d%d",&x,&y); printf("%lld\n",query(x,y)); } }