题目链接:
题意:
给定一棵n个节点树,1节点是根节点,每个节点有1个值,给定q此询问,每次询问给出x和k,求以x为根节点的子树中的节点与k异或的最大值。
思路:
树链剖分的到欧拉序后,根据欧拉序建主席树就可以了,注意多组样例输入在清空时除了h[u]还有sum数组和son数组。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int nbit=30;
const int N=1e5+10;
const int MAXN=50*N;
int a[N],w[N];
int h[N],to[2*N],ne[2*N],cnt;
int sz[N],dep[N],fa[N],son[N];
int top[N],id[N],dfn,R[N];
int root[N];
int ch[MAXN][2],tot,sum[MAXN];
int n,m;
void init(){
for(int i=0;i<=tot;i++){
sum[i]=0;
}
tot=0;
dfn=0;
cnt=0;
for(int i=1;i<=n;i++){
h[i]=-1;
son[i]=0;
}
}
void add_edge(int u,int v){
to[cnt]=v;
ne[cnt]=h[u];
h[u]=cnt++;
}
void cpy(int from,int to){
ch[to][0]=ch[from][0];
ch[to][1]=ch[from][1];
sum[to]=sum[from];
return;
}
void insert(int &u,int old,ll num,int nowbit){
u=++tot;
cpy(old,u);
sum[u]++;
if(nowbit==-1)
return;
if(num&(1<<nowbit)){
insert(ch[u][1],ch[u][1],num,nowbit-1);
}
else
insert(ch[u][0],ch[u][0],num,nowbit-1);
}
int query(int s,int t,int x){
ll ans=0;
for(int i=nbit;i>=0;i--){
int c=(x>>i)&1;
if((sum[ch[t][c^1]]-sum[ch[s][c^1]])>0){
ans|=(1<<i);
t=ch[t][c^1];
s=ch[s][c^1];
}
else{
t=ch[t][c];
s=ch[s][c];
}
}
return ans;
}
//轻重
void dfs1(int u,int fat){
sz[u]=1;
dep[u]=dep[fat]+1;
fa[u]=fat;
for(int i=h[u];i!=-1;i=ne[i]){
int v=to[i];
if(v!=fat){
dfs1(v,u);
sz[u]+=sz[v];
if(!son[u]||sz[son[u]]<sz[v]){
son[u]=v;
}
}
}
}
//链剖分
void dfs2(int u,int tp){
id[u]=++dfn;
w[dfn]=a[u];
top[u]=tp;
if(son[u])
dfs2(son[u],tp);
for(int i=h[u];i!=-1;i=ne[i]){
if(to[i]!=fa[u]&&to[i]!=son[u]){
dfs2(to[i],to[i]);
}
}
R[u]=dfn;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int u,v;
for(int i=2;i<=n;i++){
scanf("%d",&u);
v=i;
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=n;i++){
insert(root[i],root[i-1],w[i],nbit);
}
int x,k;
while(m--){
scanf("%d%d",&x,&k);
printf("%d\n",query(root[id[x]-1],root[R[x]],k));
}
}
}