题目
给出一棵有n个结点的树,树根是1,每个结点给出一个value。然后给出q个询问,每个询问给出两个整数u和x,你要在以u结点为根的子树中找出一个结点v,使得val[v] xor x最大, 并输出这个最大值
分析
显而易见的可持久化字典树,只不过这次每次查询不是查询一个区间,而是查询一棵子树。那么也很简单,我们只要预处理出dfs序然后找出每个结点以它为根的子树在dfs序中的区间。然后以这个区间建可持久化字典树就可以了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=100000+10; 8 int val[maxn]; 9 int head[maxn],to[maxn],Next[maxn]; 10 int n,q,sz; 11 void add_edge(int a,int b){ 12 ++sz; 13 to[sz]=b;Next[sz]=head[a];head[a]=sz; 14 } 15 int order[maxn],L[maxn],R[maxn],num; 16 void dfs(int u,int fa){ 17 num++; 18 order[num]=val[u]; 19 L[u]=num; 20 for(int i=head[u];i!=-1;i=Next[i]){ 21 int v=to[i]; 22 if(v!=fa) 23 dfs(v,u); 24 } 25 R[u]=num; 26 } 27 int ch[maxn*2*33][2],root[maxn],sum[maxn*2*33][2],cnt,val_t[2*maxn*33]; 28 void update(int x,int y,int a,int ID){ 29 root[x]=++cnt;x=root[x]; 30 for(int i=31;i>=0;i--){ 31 int id=(a>>i)&1; 32 sum[x][id]+=sum[y][id]+1; 33 sum[x][!id]+=sum[y][!id]; 34 ch[x][!id]=ch[y][!id]; 35 ch[x][id]=++cnt; 36 memset(ch[cnt],0,sizeof(ch[cnt])); 37 val_t[cnt]=0; 38 x=ch[x][id];y=ch[y][id]; 39 } 40 val_t[x]=ID; 41 } 42 int query(int x,int y,int a){ 43 for(int i=31;i>=0;i--){ 44 int id=(a>>i)&1; 45 if(sum[x][!id]-sum[y][!id]){ 46 x=ch[x][!id],y=ch[y][!id]; 47 }else{ 48 x=ch[x][id],y=ch[y][id]; 49 } 50 } 51 return val_t[x]; 52 } 53 int main(){ 54 while(scanf("%d%d",&n,&q)!=EOF){ 55 sz=0; 56 cnt=0; 57 memset(head,-1,sizeof(head)); 58 memset(sum,0,sizeof(sum)); 59 for(int i=1;i<=n;i++){ 60 scanf("%d",&val[i]); 61 } 62 for(int i=2;i<=n;i++){ 63 int a; 64 scanf("%d",&a); 65 add_edge(a,i); 66 } 67 num=0; 68 dfs(1,-1); 69 // for(int i=1;i<=n;i++) 70 // printf("%d ",order[i]); 71 // printf(" "); 72 update(0,0,0,0); 73 for(int i=1;i<=n;i++){ 74 update(i,root[i-1],order[i],i); 75 } 76 int u,x; 77 for(int i=1;i<=q;i++){ 78 scanf("%d%d",&u,&x); 79 printf("%d ",order[query(root[R[u]],root[L[u]-1],x)]^x); 80 } 81 } 82 return 0; 83 }