P8511 [Ynoi Easy Round 2021] TEST_68

发布时间 2023-10-09 21:14:28作者: Exotic_sum

题目传送门

看到异或最大值,根据套路不妨考虑 \(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';
}