考虑点分治,将询问离线后计算重心到每一个点的线性基,然后再询问重心到每一个点的线性基,时间复杂度为$o(3600q)$,可以过(然而太菜的我写了倍增维护线性基,震惊于倍增和线性基常数之小)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 20005 4 #define oo 0x3f3f3f3f 5 #define ll long long 6 struct ji{ 7 ll a[61]; 8 }o,dp[N][21]; 9 struct ji2{ 10 int nex,to; 11 }edge[N<<1]; 12 int E,n,m,x,y,head[N],in[N],out[N],f[N][21]; 13 ll a[N]; 14 bool pd(int x,int y){ 15 return (in[x]<=in[y])&&(out[y]<=out[x]); 16 } 17 void add(int x,int y){ 18 edge[E].nex=head[x]; 19 edge[E].to=y; 20 head[x]=E++; 21 } 22 void add(ji &x,ll y){ 23 for(int i=60;i>=0;i--) 24 if (y&(1LL<<i)) 25 if (x.a[i])y^=x.a[i]; 26 else{ 27 x.a[i]=y; 28 break; 29 } 30 } 31 void merge(ji &x,ji y){ 32 for(int i=0;i<=60;i++) 33 if (y.a[i])add(x,y.a[i]); 34 } 35 void dfs(int k,int fa){ 36 in[k]=++x; 37 f[k][0]=fa; 38 add(dp[k][0],a[k]); 39 for(int i=1;i<=20;i++){ 40 f[k][i]=f[f[k][i-1]][i-1]; 41 dp[k][i]=dp[k][i-1]; 42 merge(dp[k][i],dp[f[k][i-1]][i-1]); 43 } 44 for(int i=head[k];i!=-1;i=edge[i].nex) 45 if (edge[i].to!=fa)dfs(edge[i].to,k); 46 out[k]=++x; 47 } 48 ji calc(int x,int y){ 49 if (x==y)return dp[x][0]; 50 ji z; 51 memset(z.a,0,sizeof(z.a)); 52 for(int i=20;i>=0;i--) 53 if (!pd(f[x][i],y)){ 54 merge(z,dp[x][i]); 55 x=f[x][i]; 56 } 57 for(int i=20;i>=0;i--) 58 if (!pd(f[y][i],x)){ 59 merge(z,dp[y][i]); 60 y=f[y][i]; 61 } 62 merge(z,dp[x][pd(x,y)^1]); 63 if (!pd(y,x))merge(z,dp[y][0]); 64 return z; 65 } 66 ll query(ji o){ 67 ll ans=0; 68 for(int j=60;j>=0;j--) 69 if ((ans&(1LL<<j))==0)ans^=o.a[j]; 70 return ans; 71 } 72 int main(){ 73 scanf("%d%d",&n,&m); 74 memset(head,-1,sizeof(head)); 75 for(int i=1;i<=n;i++)scanf("%lld",&a[i]); 76 for(int i=1;i<n;i++){ 77 scanf("%d%d",&x,&y); 78 add(x,y); 79 add(y,x); 80 } 81 dfs(1,1); 82 for(int i=1;i<=m;i++){ 83 scanf("%d%d",&x,&y); 84 printf("%lld\n",query(calc(x,y))); 85 } 86 }