本文版权归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; } //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。