题意:
给定一棵树,每个点有一个权值,每次询问以u为根的子树里,结点与x异或的最大值。
题解:
离线操作,用树上启发式合并维护trie树,在每个节点上时分别查询x保存起来。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll rd(){
ll x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
return x*f;
}
const int maxn=1e5+5;
const ll mod=998244353;
int head[maxn],tot;
struct nn{int v,nxt;}g[maxn<<1];
void add_edge(int u,int v){g[++tot]={v,head[u]};head[u]=tot;}
ll n,q,a[maxn],son[maxn],cnt[maxn],sz[maxn],ans[maxn];
struct node{
int x,p;
};
vector<node>v[maxn];
struct trie{
static const int B=30;
struct node{
int to[2],num;
int &operator[](int n){return to[n];}
}a[maxn<<5];
int t;
void init(){t=0;a[t++]=node();}
void update(ll s,int v){
int k=0;
for (int i=B-1;i>=0;i--){
int c=(s>>i)&1;
if (!a[k][c])a[k][c]=t,a[t++]=node();
k=a[k][c];
a[k].num+=v;
}
}
ll query(ll s){
int k=0; ll ans=0;
for (int i=B-1;i>=0;i--){
int c=((s>>i)&1)^1;
if (a[k][c]&&a[a[k][c]].num){
ans^=1ll<<i;
}
else{
c^=1;
}
k=a[k][c];
}
return ans;
}
}t;
void init(int u,int fa){
sz[u]=1;son[u]=0;
for (int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if (v==fa)continue;
init(v,u);
if (sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs(int u,int fa,int va){
t.update(a[u],va);
for (int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if (v==fa)continue;
dfs(v,u,va);
}
}
void dsu(int u,int fa,int op){
for (int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if (v==fa||v==son[u])continue;
dsu(v,u,1);
}
if (son[u])dsu(son[u],u,0);
for (int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if (v==fa||v==son[u])continue;
dfs(v,u,1);
}
t.update(a[u],1);
for (auto i:v[u]){
ans[i.p]=t.query(i.x);
}
if (op){
t.update(a[u],-1);
for (int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if (v==fa)continue;
dfs(v,u,-1);
}
}
}
int main() {
while (~scanf("%lld%lld",&n,&q)){
for (int i=1;i<=n;i++)head[i]=cnt[i]=0,v[i].clear();tot=0;t.init();
for (int i=1;i<=n;i++)a[i]=rd();
for (int i=2,v;i<=n;i++){
v=rd();
add_edge(v,i);
add_edge(i,v);
}
for (int i=1,u,x;i<=q;i++){
u=rd();x=rd();
v[u].push_back({x,i});
}
init(1,0);
dsu(1,0,1);
for (int i=1;i<=n;i++)printf("%lld\n",ans[i]);
}
return 0;
}