本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:CF741D

正解:$dsu$ $on$ $tree$

解题报告:

  对于这种回文串的问题,很显然出现次数为奇数的个数$<=1$,那么这个状态就可以状压了。

  用$S$表示从这个点到根的字母奇偶性情况,因为$<=1$,我们特判掉$0$之后就只需要考虑有一位的情况,枚举这一位,可以唯一地得到一个状态,来满足条件,那么就可以做了。

  考虑处理一个节点时,首先可以顺便处理掉从根到子树内某个点的情况,然后我们只需要考虑子树内两个点组合而成的情况。

  用一个数组记一下每种状态的最大深度就$over$了…

  有一个小$trick$:必须要用子树中的最优值往上更新…

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
#include <bitset>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 500011;
const int MAXM = 1000011;
int n,father[MAXN],ecnt,first[MAXN],to[MAXM],next[MAXM],size[MAXN],son[MAXN],deep[MAXN],ans[MAXN],Max,s[MAXN],f[10000011]/*!!!数组开小了!!!*/,inf;
char ch[MAXN];
inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void dfs(int x,int fa){
size[x]=1; if(fa) s[x]=s[fa]^(1<<(ch[x]-'a'));
for(int i=first[x];i;i=next[i]) {
int v=to[i]; deep[v]=deep[x]+1;
dfs(v,x); size[x]+=size[v];
if(size[v]>size[son[x]]) son[x]=v;
}
} inline void calc(int rt,int x){
int state=s[x];
Max=max(Max,f[state]+deep[x]-2*deep[rt]);
if ((s[x]^s[rt])==0) Max=max(Max,deep[x]-deep[rt]);
for (int i=0;i<22;++i) {
state=(1<<i)^s[x];
Max=max(Max,f[state]+deep[x]-2*deep[rt]);
if ((s[x]^s[rt])==(1<<i)) Max=max(Max,deep[x]-deep[rt]);
}
for (int i=first[x];i;i=next[i])
calc(rt,to[i]);
} inline void change(int x,int type){
if(type) f[s[x]]=max(f[s[x]],deep[x]);
else f[s[x]]=inf; for(int i=first[x];i;i=next[i])
change(to[i],type);
} inline void solve(int x,bool top){
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==son[x]) continue;
solve(v,1);
} if(son[x])
solve(son[x],0); Max=0; int S=s[x],nows;
Max=max(Max,f[S]-deep[x]);
for(int i=0;i<22;i++) {
nows=(1<<i)^s[x];
Max=max(Max,f[nows]-deep[x]);
} for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==son[x]) continue;
calc(x,v);
change(v,1);
} ans[x]=Max; if(top) {
for(int i=first[x];i;i=next[i])
change(to[i],0);
f[s[x]]=inf;
}
else f[s[x]]=max(f[s[x]],deep[x]);
} inline void upd(int x){
for(int i=first[x];i;i=next[i]) {
upd(to[i]);
ans[x]=max(ans[x],ans[to[i]]);
}
} inline void work(){
n=getint(); for(int i=2;i<=n;i++) father[i]=getint(),link(father[i],i),scanf("%c",&ch[i]);
deep[1]=0;
dfs(1,0); memset(f,-0x7f,sizeof(f)); inf=f[0];
solve(1,1);
upd(1);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
} int main()
{
work();
return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

05-15 00:10