运用点分治的思想,dsu的处理方式,每个点作为根只考虑跨过自己的最大路径长度
对于其他路径,直接由子树继承即可
开桶max_dep[i]记录子树中到根节点1路径上信息异或和为i的最大节点深度。
考虑跨过自己的最大路径长度分两种,
第一种是端点在不同子树,对于每个子树,先更新根的ans,再更新max_dep
第二种是根节点为一端点,另一端点在子树中的,统计完第一种统计这个即可
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define rint register int
using namespace std;
const int maxn=5e5+5;
const int maxs=1<<22;
const int INF=0x3f3f3f3f;
int n,cnt;
int head[maxn];
int siz[maxn],son[maxn],dep[maxn];
int max_dep[maxs],dis[maxn];
int ans[maxn];
struct Edge{
int to,next;
}e[maxn];
void Aedge(int x,int y){
e[++cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
void dfs1(int x){
siz[x]=1;
for(int i=head[x];i;i=e[i].next){
const rint y=e[i].to;
dis[y]^=dis[x],dep[y]=dep[x]+1;
dfs1(y);
siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]]) son[x]=y;
}
}
void upd_ans(int rt,int x){
ans[rt]=max(ans[rt],max_dep[dis[x]]+dep[x]-dep[rt]*2);
for(int i=0;i<=21;++i) ans[rt]=max(ans[rt],max_dep[dis[x]^(1<<i)]+dep[x]-dep[rt]*2);
for(int i=head[x];i;i=e[i].next) upd_ans(rt,e[i].to);
}
void upd_max_dep(int x){
max_dep[dis[x]]=max(max_dep[dis[x]],dep[x]);
for(int i=head[x];i;i=e[i].next) upd_max_dep(e[i].to);
}
void cle(int x){
max_dep[dis[x]]=-INF;
for(int i=head[x];i;i=e[i].next) cle(e[i].to);
}
void dfs(int x,int op){
for(int i=head[x];i;i=e[i].next){
const rint y=e[i].to;
if(y!=son[x]) dfs(y,0),ans[x]=max(ans[x],ans[y]);
}
if(son[x]) dfs(son[x],1),ans[x]=max(ans[x],ans[son[x]]);
for(int i=head[x];i;i=e[i].next){
const rint y=e[i].to;
if(y!=son[x]) upd_ans(x,y),upd_max_dep(y);
}
ans[x]=max(ans[x],max_dep[dis[x]]-dep[x]);
for(int i=0;i<=21;++i) ans[x]=max(ans[x],max_dep[dis[x]^(1<<i)]-dep[x]);
max_dep[dis[x]]=max(max_dep[dis[x]],dep[x]);
if(!op) cle(x);
}
int main(){
//freopen("1.in","r",stdin);
memset(max_dep,-INF,sizeof max_dep);
scanf("%d",&n);
for(int i=2,x;i<=n;++i){
char ss;
scanf("%d %c",&x,&ss);
Aedge(x,i),dis[i]=1<<(ss-'a');
}
dfs1(1);
dfs(1,0);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
printf("
");
return 0;
}