質問の意味:
所与\(N- \)ツリー点、各側は文字がある(\(A \ V \)に、CO (\ 22 \) )、各サブツリー、前記最長のクエリの満足:文字セットがパス文字列の回文のパス長に再結合することができます。
データ範囲:\(N-1≤≤5. 5・10 ^ \。)
分析:
\(DSU \; \に、ツリーが\) 変更せずに木問題を解決するために使用することができます。
これは、一般的なプロセスである:各点について\(V \) 、第一のサブツリートラバーサル自分の息子の光、トラバーサルが完了した後に、その影響を除去します。最後に、彼の息子の再反復影響を保持します。その後、ポイント\(V \)と(等価再びポイントを横断する彼の息子の重量に追加され、光のすべての息子たちに影響を与える(V \)\サブツリーが根付いたが、サブツリーの息子の体重を横断していません)。暴力に対して(O(N ^ 2)\ \) アプローチは、光スポットのみ息子の第二パスです。複雑さを最適化することができることを示すことが可能に\(O(nlogn)\) 、およびブロックが美しい暴力の通りです。
XOR圧縮の使用と状態のこの質問の嘘のトリック。各文字が割り当てられている\(2 \)のバイナリビット、XORルートノードへの各点の事前値。条件を満たすパス、排他後のすべての文字の結果についてORである\(0 \)または\(2 ^ X \)フォーム。偶数パスのエンドポイントのために\(U \)と\(V \) 、両方の\(LCA \)ルートノードへのパスが二回繰り返され、キャンセルすることができます。その後、ポイントの\(V \)最長パスサブツリー二場合がある条件を満たす。
1.ポイント\(V \)パスインチ
2.ポイントは\(V \)限り、あなたは最高の息子を見つけることができるように、パス上にありません。
タイトルは、各XOR値の最大深さへの影響が配置されます。
フーに初期化注( - INF \)\ではなく、フー\(0 \) 。
コード:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=5e5+5;
const int maxn=1e7;
int son[N],sz[N],depth[N],xr[N],ans[N];
int d[maxn];
vector<int>G[N];
void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
void dfs1(int v,int d)
{
sz[v]=1;
depth[v]=d;
son[v]=0;
for(int i=0;i<G[v].size();i++)
{
int u=G[v][i];
xr[u]^=xr[v];
dfs1(u,d+1);
sz[v]+=sz[u];
if(sz[u]>sz[son[v]])
son[v]=u;
}
}
void add(int v)
{
d[xr[v]]=max(d[xr[v]],depth[v]);
for(int i=0;i<G[v].size();i++)
add(G[v][i]);
}
void an(int v,int tp)
{
ans[tp]=max(ans[tp],depth[v]+d[xr[v]]);
for(int i=0;i<22;i++)
ans[tp]=max(ans[tp],depth[v]+d[(1<<i)^xr[v]]);
for(int i=0;i<G[v].size();i++)
an(G[v][i],tp);
}
void del(int v)
{
d[xr[v]]=-inf;
for(int i=0;i<G[v].size();i++)
del(G[v][i]);
}
void dfs2(int v,bool f)
{
for(int i=0;i<G[v].size();i++)
{
int u=G[v][i];
if(u==son[v]) continue;
dfs2(u,false);
}
if(son[v])
dfs2(son[v],true);
for(int i=0;i<G[v].size();i++)
{
if(G[v][i]!=son[v])
an(G[v][i],v),add(G[v][i]);//为了保证路径一定过点v
}
d[xr[v]]=max(d[xr[v]],depth[v]);
ans[v]=max(ans[v],d[xr[v]]+depth[v]);//cout<<v<<" = "<<ans[v]<<endl;
for(int i=0;i<22;i++)
ans[v]=max(ans[v],depth[v]+d[(1<<i)^xr[v]]);//
ans[v]-=(depth[v]*2);//减去重复的部分
for(int i=0;i<G[v].size();i++)//点v不在路径中,从儿子节点中找
ans[v]=max(ans[v],ans[G[v][i]]);
if(!f)//轻儿子要清空
del(v);
}
int main()
{
int n,u;
char op[5];
read(n);
fill(d+1,d+(1<<22),-inf);//注意初始化为-inf
for(int i=2;i<=n;i++)
{
read(u);
scanf("%s",op);
G[u].pb(i);
xr[i]^=(1<<(op[0]-'a'));//每个字母分配二进制的一位
}
dfs1(1,0);//for(int i=1;i<=n;i++) cout<<" son="<<son[i];cout<<endl;
dfs2(1,0);
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i==n?'\n':' ');
return 0;
}