维护两颗可持久化字典树(当然可以放在一起),第一棵维护每一个点到根的每一位的二进制数量,在其父亲的基础上建立;第二棵维护dfs序上每一个点到第1个点的二进制数量,在其上一个点的基础上建立。
对于询问1,在第二棵上询问该子树对应区间;对于询问2,拆成x~lca和lca~y两段询问,询问时直接贪心即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define s(k,p) tr[k].son[p] 4 #define zt s(k1,p),s(k2,p),x,y-1 5 #define P ((x&(1<<y))>0) 6 #define N 100005 7 struct ji{ 8 int nex,to; 9 }edge[N<<1]; 10 struct ji2{ 11 int sum,son[2]; 12 }tr[80*N]; 13 int V,E,n,q,p,x,y,z,sz[N],head[N],r[N<<1],in[N],out[N],f[N][21],a[N],id[N]; 14 void add(int x,int y){ 15 edge[E].nex=head[x]; 16 edge[E].to=y; 17 head[x]=E++; 18 } 19 bool pd(int x,int y){ 20 return (in[x]<=in[y])&&(out[y]<=out[x]); 21 } 22 int lca(int x,int y){ 23 if (pd(x,y))return x; 24 for(int i=20;i>=0;i--) 25 if (!pd(f[x][i],y))x=f[x][i]; 26 return f[x][0]; 27 } 28 void ins(int k1,int &k2,int x,int y){ 29 tr[k2=++V]=tr[k1]; 30 tr[k2].sum++; 31 if (y<0)return; 32 bool p=P; 33 ins(zt); 34 } 35 int query(int k1,int k2,int x,int y){ 36 if (y<0)return 0; 37 bool p=(tr[s(k1,P^1)].sum<tr[s(k2,P^1)].sum)^P; 38 return (P^p)*(1<<y)+query(zt); 39 } 40 int dfs(int k,int fa){ 41 ins(r[fa],r[k],a[k],30); 42 f[k][0]=fa; 43 in[k]=++x; 44 id[x]=k; 45 sz[k]=1; 46 for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1]; 47 for(int i=head[k];i!=-1;i=edge[i].nex) 48 if (edge[i].to!=fa)sz[k]+=dfs(edge[i].to,k); 49 out[k]=x; 50 return sz[k]; 51 } 52 int main(){ 53 scanf("%d%d",&n,&q); 54 memset(head,-1,sizeof(head)); 55 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 56 for(int i=1;i<n;i++){ 57 scanf("%d%d",&x,&y); 58 add(x,y); 59 add(y,x); 60 } 61 x=0; 62 dfs(1,1); 63 f[1][0]=0; 64 for(int i=1;i<=n;i++)ins(r[i+n],r[i+n+1],a[id[i]],30); 65 for(int i=1;i<=q;i++){ 66 scanf("%d%d%d",&p,&x,&y); 67 if (p==1)printf("%d\n",query(r[in[x]+n],r[in[x]+sz[x]+n],y,30)); 68 else{ 69 scanf("%d",&z); 70 p=f[lca(x,y)][0]; 71 printf("%d\n",max(query(r[p],r[x],z,30),query(r[p],r[y],z,30))); 72 } 73 } 74 }