感觉dsu on tree一定程度上还是与点分类似的。考虑求出跨过每个点的最长满足要求的路径,再对子树内取max即可。
重排后可以变成回文串相当于出现奇数次的字母不超过1个。考虑dsu on tree,容易想到遍历时记录每种情况的最大深度,合并时类似点分的逐个计算贡献再合并即可。这里有个问题是得到某子树信息后,对于原来的根来说,这个信息还要再加上一个偏移量,但直接暴力显然复杂度就不对了。实际上维护信息过程中不断传递偏移量即可。
一开始就发现了这个题只开了256M,于是机智的开了个map,悲惨的T掉了。然而题面里深藏不露的说了一句字母范围在a~v。这啥思博题啊。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 500010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N],p[N],fa[N],size[N],deep[N],son[N],len[N],ans[N],t,f[1<<22]; struct data{int to,nxt; }edge[N]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],len[y]=z,p[x]=t;} void make(int k) { size[k]=1; for (int i=p[k];i;i=edge[i].nxt) { deep[edge[i].to]=deep[k]+1; make(edge[i].to); size[k]+=size[edge[i].to]; if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to; } } inline int rev(int x){return (1<<22)-1^x;} void update(int k,int x,int op) { if (op==1) f[k]=max(f[k],x); else f[k]=0; } void add(int k,int x,int op)//对子树内统计信息时,偏移量为x { update(x,deep[k],op); for (int i=p[k];i;i=edge[i].nxt) add(edge[i].to,x^(1<<len[edge[i].to]),op); } int calc(int k,int x) { int ans=f[x]+deep[k]; for (int i=0;i<22;i++) ans=max(ans,deep[k]+f[x^(1<<i)]); if (ans==deep[k]) ans=-N; for (int i=p[k];i;i=edge[i].nxt) ans=max(ans,calc(edge[i].to,x^(1<<len[edge[i].to]))); return ans; } int dfs(int k)//获得的该子树信息的偏移量 { for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=son[k]) { int delta=dfs(edge[i].to); ans[k]=max(ans[k],ans[edge[i].to]); add(edge[i].to,delta,-1); } int delta=0; if (son[k]) { delta=dfs(son[k])^(1<<len[son[k]]);ans[k]=max(ans[k],ans[son[k]]); for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=son[k]) { ans[k]=max(ans[k],calc(edge[i].to,delta^(1<<len[edge[i].to]))-(deep[k]<<1)); add(edge[i].to,delta^(1<<len[edge[i].to]),1); } } ans[k]=max(ans[k],f[delta]-deep[k]); for (int i=0;i<22;i++) ans[k]=max(ans[k],f[delta^(1<<i)]-deep[k]); update(delta,deep[k],1); return delta; } int main() { #ifndef ONLINE_JUDGE freopen("741D.in","r",stdin); freopen("741D.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); for (int i=2;i<=n;i++) fa[i]=read(),addedge(fa[i],i,getc()-'a'); deep[1]=1;make(1); dfs(1); for (int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }