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;
}

posted @ 2023-03-20 22:17  fzj2007  阅读(79)  评论(0)    收藏  举报