题目概述
给出一棵
n
个节点的树,边权是小写字母(
解题报告
询问子树不修改果断上dsu on tree。能打乱排列成回文说明至多只有一个字母出现了奇数次,因为字母只有
示例程序
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=500000,maxs=1<<22;
int n,si[maxn+5],dep[maxn+5],sum[maxn+5],SH[maxn+5];
int E,lnk[maxn+5],son[maxn+5],nxt[maxn+5],w[maxn+5];
int now,MAX,MD[maxs+5],ans[maxn+5];bool vis[maxn+5];
#define Add(x,y,z) son[++E]=(y),w[E]=(z),nxt[E]=lnk[x],lnk[x]=E
inline char getlwr() {char ch=getchar();while (!islower(ch)) ch=getchar();return ch;}
void HLD(int x)
{
si[x]=1;
for (int j=lnk[x];j;j=nxt[j])
{
dep[son[j]]=dep[x]+1;sum[son[j]]=sum[x]^(1<<w[j]);
HLD(son[j]);si[x]+=si[son[j]];
if (si[son[j]]>si[SH[x]]) SH[x]=son[j];
}
}
inline void getMAX(int x)
{
if (MD[sum[x]]) MAX=max(MAX,dep[x]+MD[sum[x]]-(now<<1));
for (int j=0;j<22;j++) if (MD[sum[x]^(1<<j)])
MAX=max(MAX,dep[x]+MD[sum[x]^(1<<j)]-(now<<1));
}
void Update(int x) {getMAX(x);for (int j=lnk[x];j;j=nxt[j]) Update(son[j]);}
inline void Fix(int x) {if (dep[x]>MD[sum[x]]) MD[sum[x]]=dep[x];}
void Insert(int x) {Fix(x);for (int j=lnk[x];j;j=nxt[j]) Insert(son[j]);}
void Delete(int x) {MD[sum[x]]=0;for (int j=lnk[x];j;j=nxt[j]) Delete(son[j]);}
void Solve(int x,bool fl=true)
{
for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=SH[x]) Solve(son[j],false);
if (SH[x]) Solve(SH[x],true);now=dep[x];
for (int j=lnk[x];j;j=nxt[j]) ans[x]=max(ans[x],ans[son[j]]);
for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=SH[x])
Update(son[j]),Insert(son[j]);
getMAX(x);Fix(x);ans[x]=max(ans[x],MAX);if (!fl) Delete(x),MAX=0;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&n);for (int i=2,x;i<=n;i++) scanf("%d",&x),Add(x,i,getlwr()-'a');
HLD(1);Solve(1);for (int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}