問題の説明
念のために誰かがそれを逃した:私たちはアルパの土地で素晴らしい女の子を持っています。
ARPAは、以下からなるルート付きツリー(接続非巡回グラフ)を有するn個の頂点を。頂点が1through番号が付されているN、頂点1がルートです。このツリーの各エッジに書かれた手紙があります。MehrdadはDokhtar-kosh物事のファンです。我々はそれが回文になるように、文字列内の文字をシャッフルすることができれば、彼は、文字列Dokhtar-koshを呼び出します。
彼はアルパは、各頂点を要求V、のサブツリーで最長の単純なパスの長さは何であるV Dokhtar-kosh文字列を形成します。
入力形式
最初の行は、整数含まN(1≤ nは ツリーの頂点の数- ≤5・105)。
(N - 1)行は、次のI番目のそれらの整数含むP I + 1と文字 C I + 1(1≤ P iは + 1≤ iは、 C I + 1との間で、小文字の英文字であるとV、包括的に)、それは、ノード間のエッジがあることを意味P I + 1と I + 1と文字がある cを I + 1は、このエッジに書き込まは。
出力フォーマット
印刷nは整数です。I番目のそれらのは、サブツリー内の最長の単純な経路の長さであるべきであるI番目の頂点Dokhtar-koshストリングを形成します。
サンプル入力と出力
例
入力
4
1、S
2
3秒
出力
3 1 1 0
入力
1
2時間
1
4時間
出力
4 1 0 1 0
問題の意味を総括
ツリーは、それぞれの側は、パス文字列へのルート・ノード・ポイントの並び替え後のこのパス上のすべての文字がパリンドロームで構成することができるように、それらのそれぞれは、サブツリー最長の簡単なパスを求め、手紙を持っています。
解決
回文文字列:最初のステップは、我々は最も特別なことのトピックを分析する必要があります。文字列は、回文文字列である場合と奇数の出現までの文字列がある場合のみ。私たちは、私たちは明確に各列のパリティ出現数を知ることができます文字列を表現する構造を必要としています。わずか22文字ので、我々は圧縮状態でき、文字回の奇数1、又は0偶数た各位置に出現は、XOR動作を実現するために使用することができます。
それは、サブツリーの問題であるので、我々は書くために、ツリーのヒューリスティックマージを使用することができます。セット\([i]が\ F)の状態を示し\を(私は\)最も長い文字列の最大深さ(文字列は二つのサブツリーに必要とされない)、次いで、答えは現在のノードがあると仮定するたびに更新\ (X \) 、ルートノードがから(X \)\リアパス状態に圧縮されている\(XOR [X] \) 。以下の2つのケースについて議論します:
1ストリングのサブツリーのルートノードを横断しません。この時点で、2つのケースがあります。
\(F [XOR [X] ] \) サブツリーツリーに記載の値は、パスが場合もある持っている\(X \)特定のパリンドローム配列のルート・ノード・パスとを構築することができる(または合計排他後0)。したがって、
\ [ANS [X] =最大 (ANS [X]、F [XOR [X]])\]パスの要件を満たしているものとする\(パス\) 、次いで\(XOR [X] ^パスが \) 結果は、1又は0満杯でなければなりません。したがって、XOR演算の性質は、直接であってもよい\(XOR [X] ^( 1 << I)\) 次に、回答を更新し、要件を満たすために状態を与えるために、ある
\ [ANSは、[X] =最大 (ANS [X ]、F [XOR [X] \ oplus(1 << I)])\]
それと同時に、また、対応する更新\(F \)の値、
\ [F [XOR [X] = MAX(F [XOR [SUM]、DEP [X])\] \(DEP [X]を\)これは、点表す\(x \)の深さ。
サブツリールート全体で2列。その後、我々は、ケース1と同じ方法でできますが、子供は、ツリー内の各ノードの統計答えを持っています。詳細アナログタイムスタンプは、再帰的にサブツリーを使用することができます。また、各サブツリーを横断し、我々はそれを更新するために覚えておく必要があります\(F \) 。
コード
#include <iostream>
#include <cstdio>
#define N 500002
using namespace std;
int head[N],ver[N],nxt[N],edge[N],l;
int n,i,son[N],size[N],dep[N],sum[N],dfn[N],low[N],rec[N],ans[N],tim,f[1<<23];
void insert(int x,int y,char z)
{
l++;
ver[l]=y;
edge[l]=(1<<(int)(z-'a'));
nxt[l]=head[x];
head[x]=l;
}
void dfs(int x,int pre)
{
dfn[x]=++tim;rec[tim]=x;
size[x]=1;dep[x]=dep[pre]+1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre){
sum[y]=sum[x]^edge[i];
dfs(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) son[x]=y;
}
}
low[x]=tim;
}
void dsu(int x,int pre)
{
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=son[x]){
dsu(y,x);
ans[x]=max(ans[x],ans[y]);
for(int j=dfn[y];j<=low[y];j++) f[sum[rec[j]]]=0;
}
}
if(son[x]>0){
dsu(son[x],x);
ans[x]=max(ans[x],ans[son[x]]);
}
if(f[sum[x]]) ans[x]=max(ans[x],f[sum[x]]-dep[x]);
for(int i=0;i<22;i++){
if(f[sum[x]^(1<<i)]) ans[x]=max(ans[x],f[sum[x]^(1<<i)]-dep[x]);
}
f[sum[x]]=max(f[sum[x]],dep[x]);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=son[x]){
for(int j=dfn[y];j<=low[y];j++){
int z=rec[j];
if(f[sum[z]]) ans[x]=max(ans[x],f[sum[z]]+dep[z]-2*dep[x]);
for(int k=0;k<22;k++){
if(f[sum[z]^(1<<k)]) ans[x]=max(ans[x],f[sum[z]^(1<<k)]+dep[z]-2*dep[x]);
}
}
for(int j=dfn[y];j<=low[y];j++){
int z=rec[j];
f[sum[z]]=max(f[sum[z]],dep[z]);
}
}
}
}
int main()
{
cin>>n;
for(i=1;i<n;i++){
int u;char w;
cin>>u>>w;
insert(u,i+1,w);
}
dfs(1,0);
dsu(1,0);
for(i=1;i<=n;i++) cout<<ans[i]<<' ';
cout<<endl;
return 0;
}