题意:
给定n个顶点的树,树根为1,
每个点有点权a(i),
q次询问,每次询问给出u,x
要求在以u为根的子树中,找到一个点,
满足这个点与x的异或值最大,输出这个最大异或值。
数据范围:n,q<=1e5
解法:
子树问题可以用dfs序转化为区间问题,
那么每个询问就变为在区间[l,r]上的查询.
在序列上建可持久化01字典树就行了.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
vector<int>g[maxm];
int ans[maxm];
int a[maxm];
int n,q;
//
int nt[maxm*60][2];
int cnt[maxm*60];
int rt[maxm],tot;
void add(int x,int last,int k){
for(int i=30;i>=0;i--){
int v=(x>>i&1);
//copy
nt[k][0]=nt[last][0];
nt[k][1]=nt[last][1];
//
tot++;
nt[tot][0]=nt[tot][1]=0;
nt[k][v]=tot;
//
k=nt[k][v];
last=nt[last][v];
cnt[k]=cnt[last]+1;
}
}
int ask(int x,int l,int r){
int ans=0;
for(int i=30;i>=0;i--){
int v=(x>>i&1);
if(cnt[nt[r][v^1]]-cnt[nt[l][v^1]]){
r=nt[r][v^1];
l=nt[l][v^1];
ans+=(1<<i);
}else{
r=nt[r][v];
l=nt[l][v];
}
}
return ans;
}
//
int L[maxm],R[maxm],idx;
int rk[maxm];
void dfs(int x){
L[x]=++idx;
rk[idx]=x;
for(int v:g[x]){
dfs(v);
}
R[x]=idx;
}
//
void init(){
tot=0;
nt[tot][0]=nt[tot][1]=0;
rt[tot]=0;
idx=0;
}
signed main(){
while(scanf("%d%d",&n,&q)!=EOF){
init();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)g[i].clear();
for(int i=2;i<=n;i++){
int fa;scanf("%d",&fa);
g[fa].push_back(i);
}
dfs(1);
for(int i=1;i<=n;i++){
//
tot++;
nt[tot][0]=nt[tot][1]=0;
//
rt[i]=tot;
add(a[rk[i]],rt[i-1],rt[i]);
}
while(q--){
int u,x;scanf("%d%d",&u,&x);
int ans=ask(x,rt[L[u]-1],rt[R[u]]);
printf("%d\n",ans);
}
}
return 0;
}