每个节点建一颗字典树,启发式合并就好了。
内存n*logn*logn,内存超限,考虑合并完之后废弃的字典树的节点存一下,后面再次利用。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int tree[maxn*55][2],a[maxn];
vector<int>G[maxn],S[maxn],ask1[maxn],ask2[maxn];
int n,q,tol,root[maxn],ans[maxn];
int que[maxn*55],top;
void Insert(int c,int x)
{
for(int i=30;i>=0;i--)
{
int t=(x>>i&1);
if(tree[c][t]==0)
{
int cnt;
if(top) cnt=que[top--];
else cnt=++tol;
tree[c][t]=cnt;
tree[cnt][0]=tree[cnt][1]=0;
}
c=tree[c][t];
}
}
int query(int c,int x)
{
int ans=0;
for(ll i=30;i>=0;i--)
{
int t=(x>>i&1);
if(tree[c][t^1])
ans|=(1<<i),c=tree[c][t^1];
else
c=tree[c][t];
}
return ans;
}
void del(int c)
{
if(tree[c][0])
del(tree[c][0]);
if(tree[c][1])
del(tree[c][1]);
que[++top]=c;
tree[c][0]=tree[c][1]=0;
}
void dfs(int v)
{
Insert(root[v],a[v]);
S[root[v]].push_back(a[v]);
for(int i=G[v].size()-1;i>=0;i--)
{
int to=G[v][i];
dfs(to);
if(S[root[v]].size()>=S[root[to]].size())
{
for(int j=S[root[to]].size()-1;j>=0;j--)
{
Insert(root[v],S[root[to]][j]);
S[root[v]].push_back(S[root[to]][j]);
}
del(root[to]);
}
else
{
for(int j=S[root[v]].size()-1;j>=0;j--)
{
Insert(root[to],S[root[v]][j]);
S[root[to]].push_back(S[root[v]][j]);
}
del(root[v]);
root[v]=root[to];
}
}
for(int i=ask1[v].size()-1;i>=0;i--)
{
int t=ask2[v][i],x=root[v],y=ask1[v][i];
ans[t]=query(x,y);
}
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
//memset(tree,0,sizeof(tree));
for(int i=0;i<maxn;i++)
{
G[i].clear();
S[i].clear();
ask1[i].clear();
ask2[i].clear();
}
top=tol=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
root[i]=++tol;
tree[tol][0]=tree[tol][1]=0;
}
for(int i=2;i<=n;i++)
{
int x;scanf("%d",&x);
G[x].push_back(i);
}
for(int i=1;i<=q;i++)
{
int v,x;scanf("%d%d",&v,&x);
ask1[v].push_back(x);
ask2[v].push_back(i);
}
dfs(1);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
}