理解上面两题之后此题就变得很套路了。
先用 D F S DFS DFS序转树形结构为线性结构,然后按 D F S DFS DFS序的顺序向字典树中插值,维护一个前缀字典树,然后利用可持久化保留每一个插值前的字典树历史版本。
因为一个以 u u u节点为根的子树的所有节点在 D F S DFS DFS序中连续,且为 i n [ u ] − o u t [ u ] in[u]-out[u] in[u]−out[u]。
故利用差分的思想,可实现高效查询。
注意特判子树根的异或和。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int A = 2e5 + 10;
class Gra{
public:
int v,next;
}G[A<<2];
class Trie{
public:
int ne[2],cnt;
}T[A<<5];
int head[A],val[A],in[A],out[A],id[A],root[A];
int tot,twt,n,q;
void init(){
tot = twt = root[0] = T[0].cnt = 0;
memset(T[0].ne,0,sizeof(T[0].ne));
memset(head,-1,sizeof(head));
}
void add(int u,int v){ G[tot].v = v;G[tot].next = head[u];head[u] = tot++;}
void dfs(int u,int pre){
in[u] = ++twt;
id[twt] = u;
for(int i = head[u] ;i!=-1 ;i=G[i].next){
int v = G[i].v;
if(v == pre) continue;
dfs(v,u);
}
out[u] = twt;
}
int insert(ll v,int y){
int x,res;
x = res = ++tot;T[x] = T[y];
for(int i=32 ;i>=0 ;i--){
int c = (v>>i)&1;
int tem = ++tot;
T[tem] = T[T[x].ne[c]];
T[tem].cnt++;
T[x].ne[c] = tem;
x = tem;
}
return res;
}
ll query(int u,ll v){
ll ans = v^val[u],res = 0;
int x = root[in[u]],y = root[out[u]];
for(int i=32 ;i>=0 ;i--){
int c = (v>>i)&1;
int num = T[T[y].ne[c^1]].cnt - T[T[x].ne[c^1]].cnt;
if(num>0) res |= (1<<i),c ^= 1;
x = T[x].ne[c],y = T[y].ne[c];
}
return max(ans,res);
}
void solve(){
dfs(1,0);tot = 0;
for(int i=1 ;i<=twt ;i++) root[i] = insert(val[id[i]],root[i-1]);
while(q--){
int u,x;scanf("%d%d",&u,&x);
printf("%I64d\n",query(u,x));
}
}
int main(){
while(~scanf("%d%d",&n,&q)){
init();
for(int i=1 ;i<=n ;i++) scanf("%d",&val[i]);
for(int i=2 ;i<=n ;i++){
int x;scanf("%d",&x);
add(x,i);add(i,x);
}
solve();
}
return 0;
}