来写一个\(3\)个\(log\)的垃圾做法
其实非常显然就是倍增把这条路径处理一遍,之后维护出倍增数组的线性基,大力合并就好了
线性基合并就是把一个线性基的所有元素都拿出来,一个一个插入到另外一个中去
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 20005
#define re register
#define LL long long
inline LL read() {
LL x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt;}e[maxn<<1];
int f[maxn][17];
LL a[maxn],lb[maxn][17][66];
int log_2[maxn],deep[maxn],head[maxn];
int n,num,Q;
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs(int x) {
for(re int i=head[x];i;i=e[i].nxt)
if(!deep[e[i].v]) {
deep[e[i].v]=deep[x]+1;f[e[i].v][0]=x;
dfs(e[i].v);
}
}
inline void ins(LL x,int t,int b) {
for(re int j=61;j>=0;--j)
if(x>>j&1ll) {
if(!lb[t][b][j]) {lb[t][b][j]=x;return;}
x^=lb[t][b][j];
}
}
inline void merge(int x,int y,int c,int d) {
for(re int t=61;t>=0;--t) {
if(!lb[c][d][t]) continue;
ins(lb[c][d][t],x,y);
}
}
inline void solve(int x,int y) {
memset(lb[0][0],0,sizeof(lb[0][0]));
if(x==y) {ins(a[x],0,0);return;}
if(deep[x]<deep[y]) std::swap(x,y);
for(re int i=log_2[deep[x]];i>=0;--i)
if(f[x][i]&&deep[f[x][i]]>=deep[y])
merge(0,0,x,i),x=f[x][i];
if(x==y) return;
for(re int i=log_2[deep[x]];i>=0;--i)
if(f[x][i]!=f[y][i]) {
merge(0,0,x,i),merge(0,0,y,i);
x=f[x][i],y=f[y][i];
}
ins(a[x],0,0),ins(a[y],0,0);if(f[x][0])ins(a[f[x][0]],0,0);
}
int main()
{
n=read(),Q=read();
for(re int i=1;i<=n;i++) a[i]=read();
int x,y;
for(re int i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
deep[1]=1;dfs(1);
for(re int i=2;i<=n;i++) log_2[i]=log_2[i>>1]+1;
for(re int i=1;i<=n;i++) ins(a[i],i,0);
for(re int i=1;i<=n;i++) if(f[i][0]) ins(a[f[i][0]],i,0);
for(re int j=1;j<=log_2[n];j++)
for(re int i=1;i<=n;i++) {
if(!f[i][j-1]) continue;
f[i][j]=f[f[i][j-1]][j-1];
merge(i,j,i,j-1);merge(i,j,f[i][j-1],j-1);
}
while(Q--) {
x=read(),y=read();
solve(x,y);
LL ans=0;
for(re int i=61;i>=0;--i) if((ans^lb[0][0][i])>ans) ans^=lb[0][0][i];
printf("%lld\n",ans);
}
return 0;
}