题意:
给定n个顶点的树,树根为1,
每个点有点权a(i),
q次询问,每次询问给出u,x
要求在以u为根的子树中,找到一个点,
满足这个点与x的异或值最大,输出这个最大异或值。
数据范围:n,q<=1e5
解法:
最大异或值可以用01字典树做,
对每个节点建立一棵01字典树,每个节点的字典树可以由子节点的字典树合并而来,
将询问离线,自底向上处理每个点上的询问就行了.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
vector<pair<int,int> >Q[maxm];
vector<int>g[maxm];
int ans[maxm];
int a[maxm];
int n,q;
//
int nt[maxm*60][2];//数组开大点
int rt[maxm],tot;
void add(int x,int k){
for(int i=30;i>=0;i--){
int v=(x>>i&1);
if(!nt[k][v]){
//
tot++;
nt[tot][0]=nt[tot][1]=0;
//
nt[k][v]=tot;
}
k=nt[k][v];
}
}
int ask(int x,int k){
int ans=0;
for(int i=30;i>=0;i--){
int v=(x>>i&1);
if(nt[k][v^1]){
k=nt[k][v^1];
ans+=(1<<i);
}else{
k=nt[k][v];
}
}
return ans;
}
int merged(int x,int y){
if(!x||!y)return x+y;
nt[x][0]=merged(nt[x][0],nt[y][0]);
nt[x][1]=merged(nt[x][1],nt[y][1]);
return x;
}
void dfs(int x){
//
tot++;
nt[tot][0]=nt[tot][1]=0;
//
rt[x]=tot;
add(a[x],rt[x]);
for(int v:g[x]){
dfs(v);
rt[x]=merged(rt[x],rt[v]);
}
for(auto i:Q[x]){
int k=i.first;
ans[i.second]=ask(k,rt[x]);
}
}
void init(){
tot=0;
nt[tot][0]=nt[tot][1]=0;
rt[tot]=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(),Q[i].clear();
for(int i=2;i<=n;i++){
int fa;scanf("%d",&fa);
g[fa].push_back(i);
}
for(int i=1;i<=q;i++){
int u,x;scanf("%d%d",&u,&x);
Q[u].push_back({x,i});
}
dfs(1);
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
}
return 0;
}