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  阅读(52)  评论(0)    收藏  举报