To_Heart—题解——[Ynoi2021] TEST_68
题意
题解
傻逼玩意儿,思想很简单,但是好久没写过 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;
}