P8511 [Ynoi Easy Round 2021] TEST_68
P8511 [Ynoi Easy Round 2021] TEST_68
\(\text{difficulty}={2.5,3}\)。
\(\text{tags}=\text{trie}树\)。
异或和最大,直接考虑 \(\text{01 trie}\)。注意到样例中取到最大值的点很多,那么先考虑找到一对满足异或和为最大值的点对 \((A,B)\)。
由于只要这 \(A,B\) 均不在 \(x\) 的子树内即可作为 \(x\) 的答案,经过观察发现只有 \(x\) 在 \(A,B\) 分别到根的路径上时 \(A,B\) 不能作为 \(x\) 的答案。
那么只需要对两条链 \((1,A)\) 与 \((1,B)\) 分别求出每个点的答案即可。
考虑计算 \((1,A)\)。从 \(1\) 开始向下跳链,设当前跳到 \(x\)。那么实际上向下一步走到 \(v\) 会使得能够选择的点集变大。实际上增加的部分是 \(x\) 子树除去 \(v\) 子树的剩余部分。
那么只需要每次暴力将新增的部分插入 \(\text{trie}\) 中,在插入的同时顺便维护一下点对异或的最大值即可。
时间复杂度 \(\mathcal{O}(n \log w)\)。
code
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>inline bool read(T &x){
x=0;
char ch=getchar();
bool flag=0,ret=0;
while(ch<'0'||ch>'9') flag=flag||(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(),ret=1;
x=flag?-x:x;
return ret;
}
template<typename T,typename ...Args>inline bool read(T& a,Args& ...args){
return read(a)&&read(args...);
}
template<typename T>void prt(T x){
if(x>9) prt(x/10);
putchar(x%10+'0');
}
template<typename T>inline void put(T x){
if(x<0) putchar('-'),x=-x;
prt(x);
}
template<typename T>inline void put(char ch,T x){
if(x<0) putchar('-'),x=-x;
prt(x);
putchar(ch);
}
template<typename T,typename ...Args>inline void put(T a,Args ...args){
put(a);
put(args...);
}
template<typename T,typename ...Args>inline void put(const char ch,T a,Args ...args){
put(ch,a);
put(ch,args...);
}
inline void put(string s){
for(int i=0,sz=s.length();i<sz;i++) putchar(s[i]);
}
inline void put(const char* s){
for(int i=0,sz=strlen(s);i<sz;i++) putchar(s[i]);
}
}
using namespace IO;
#define N 500005
#define M 31000005
#define K 61
#define ll long long
int n,trie[M][2],siz[M],id[M],idx;
inline void insert(ll val,int k){
int p=1;siz[p]++;
for(int i=K;~i;i--){
int c=val>>i&1;
if(!trie[p][c]) trie[p][c]=++idx;
siz[p=trie[p][c]]++;
}
id[p]=k;
}
inline pair<ll,int> query(ll val){
ll res=0,p=1;
for(int i=K;~i;i--){
int c=val>>i&1;
if(!trie[p][c^1]) p=trie[p][c];
else res|=1ll<<i,p=trie[p][c^1];
}
return make_pair(res,id[p]);
}
inline void clear(){
for(int i=1;i<=idx;i++) trie[i][0]=trie[i][1]=siz[i]=id[i]=0;
idx=1;
}
int fa[N],head[N],cnt,A,B;
ll w[N],ans[N],maxn;
bool vis[N];
struct edge{
int v,nxt;
}e[N<<1];
inline void add(int u,int v){
e[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
inline void dfs(int x){
maxn=max(maxn,query(w[x]).first),insert(w[x],0);
for(int i=head[x];i;i=e[i].nxt) dfs(e[i].v);
}
inline void solve(int p){
vector<int> path;maxn=0;clear();
while(p) vis[p]=1,path.emplace_back(p),p=fa[p];
reverse(path.begin(),path.end());
for(auto x:path){
ans[x]=maxn;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].v]) dfs(e[i].v);
maxn=max(maxn,query(w[x]).first),insert(w[x],0);
}
memset(vis,0,sizeof(vis));
}
int main(){
read(n),clear();
if(n==1) return puts("0"),0;
for(int i=2;i<=n;i++) read(fa[i]),add(fa[i],i);
for(int i=1;i<=n;i++){
read(w[i]);
pair<ll,int> res=query(w[i]);
if(res.first>ans[0]) ans[0]=res.first,A=i,B=res.second;
insert(w[i],i);
}
solve(A),solve(B);
while(A) vis[A]=1,A=fa[A];
while(B) vis[B]=1,B=fa[B];
for(int i=1;i<=n;i++)
if(!vis[i]) put('\n',ans[0]);
else put('\n',ans[i]);
return 0;
}