To_Heart—题解——[Ynoi2021] TEST_68

题意

link.

题解

傻逼玩意儿,思想很简单,但是好久没写过 trie 了,实现有点不会了。

然后就是先找到整棵树中使得最大的那两个点。发现除了这两个点到1的两条链以外,其他的点的答案就是全局最大。然后你再处理一下这两条链就好了。

细节就是,因为子树包括本身,所以说选择从链的上端往下跑。

以及有的点答案为 0,所以需要用个数组记录到底该用谁表示答案。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

vector<int> v[500005];
ll a[500005];

struct zz{
	ll w;int id;
};

int t[30000005][2];
int End[30000005];
struct Trie{
	int tot=0;
	int a[65];
	void Insert(ll x,int id){
		for(int i=59;i>=0;i--) a[i]=(x>>i)&1ll; 
		int p=0;
		for(int i=59;i>=0;i--){
			if(!t[p][a[i]]) t[p][a[i]]=++tot;
			p=t[p][a[i]];
		}
		End[p]=id;
	}
	zz Find(ll x){
		ll ans=0; 
		int p=0;
		for(int i=59;i>=0;i--) a[i]=(x>>i)&1ll;
		for(int i=59;i>=0;i--){
			if(t[p][!a[i]]) p=t[p][!a[i]],ans+=(1ll<<i);
			else p=t[p][a[i]];
		}	
		return (zz){ans,End[p]};
	}
	void clear(){
		tot=0;
		memset(t,0,sizeof t);memset(End,0,sizeof End);
	} 
}T;

int fa[2000005];
int qwq[500005];
ll ans[500005];
bool vis[500005];
ll mmax=0;

void DFS(int x){
	T.Insert(a[x],x);
	for(auto y:v[x]) DFS(y),fa[y]=x;
}
void DFS_1(int x){
	T.Insert(a[x],x);
	mmax=max(mmax,T.Find(a[x]).w);
	for(auto y:v[x]) if(!qwq[y]) DFS_1(y);
}
int n,m;
stack<int> st;

int main(){
	cin>>n;
	for(int i=2,x;i<=n;i++) scanf("%d",&x),v[x].push_back(i);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	DFS(1);
	
	ll Max=0;int xx=1,yy=1;
	for(int i=1;i<=n;i++){
		zz now=T.Find(a[i]);
		if(now.w>Max) Max=now.w,xx=i,yy=now.id;
	}
	
	memset(qwq,0,sizeof qwq);
	for(int p=xx;p!=1;p=fa[p]) st.push(p);
	
	T.clear();mmax=0;
	while(st.size()){
		int now=st.top();st.pop();
		qwq[now]=vis[now]=1;
		DFS_1(fa[now]);
		ans[now]=mmax;
	} 
	
	memset(qwq,0,sizeof qwq);
	for(int p=yy;p!=1;p=fa[p]) st.push(p);
	T.clear();mmax=0;
	while(st.size()){
		int now=st.top();st.pop();
		qwq[now]=vis[now]=1;
		DFS_1(fa[now]);
		ans[now]=mmax;
	}
	
	printf("0\n");
	for(int i=2;i<=n;i++){
		if(vis[i]) printf("%lld\n",ans[i]);
		else printf("%lld\n",Max);
	}
	return 0;
}
posted @ 2023-02-21 17:39  To_Heart  阅读(2)  评论(0编辑  收藏  举报  来源