看到异或最大值,根据套路不妨考虑 \(0-1 trie\)。
通过 \(trie\) 找到异或值最大的点对 \((x,y)\)。那么除了 \((x,y)\) 到 \(1\) 路径上的点之外,其他的点的答案就是 \((x,y)\) 的异或值。
接下来考虑怎么算出这 \((x,y)\) 到 \(1\) 路径上的点的答案,可以直接暴力计算!
具体地,先清空原来的 \(trie\),将 \(x,y\) 分别向 \(1\) 号节点递归深,回溯的时候从 \(trie\) 中找到最大异或值,然后不断在 \(trie\) 中加入此时的节点和递归它其他的子节点并一一加入。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=500001,M=30000001;
int n,x,fa[N],p,q,vis[N];
ll a[N],b[N],maxn;
vector<int> g[N];
struct trie{int tr[M][2],to[M],tot=1,px=0,py=0;
ll mx=0;
void clear(){for(int i=1;i<=tot;i++)tr[i][0]=tr[i][1]=to[i]=0;
tot=1,mx=0;
}
void add(int x){int p=1;
for(int i=59;i>=0;i--){int u=(a[x]>>i)&1;
if(!tr[p][u])tr[p][u]=++tot;
p=tr[p][u];
}
to[p]=x,p=1;
for(int i=59;i>=0;i--){int u=(a[x]>>i)&1;
if(tr[p][u^1])p=tr[p][u^1];
else if(tr[p][u])p=tr[p][u];
else return;
}
if((a[x]^a[to[p]])>mx)px=x,py=to[p],mx=(a[px]^a[py]);
}
}T;
void dfs(int u){T.add(u);
for(int v:g[u])dfs(v);
}
void dfs1(int u,int f){if(!u) return;
dfs1(fa[u],u),b[u]=T.mx,vis[u]=1,T.add(u);
if(u!=f)for(int v:g[u])if(v!=f)dfs(v);
}
int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=2;i<=n;i++)cin>>x,g[x].push_back(i),fa[i]=x;
for(int i=1;i<=n;i++)cin>>a[i],T.add(i);
p=T.px,q=T.py,maxn=T.mx,T.clear(),dfs1(p,p),T.clear(),dfs1(q,q);
for(int i=1;i<=n;i++)cout<<(vis[i]?b[i]:maxn)<<'\n';
}
标签:int,ll,tr,Ynoi,trie,异或,P8511,68,mx
From: https://www.cnblogs.com/Exotic-sum/p/17753168.html