一棵树n个点,每条边有一个字母。对于每个点,要求找到它的子树当中最长的一条路径,这条路径上的字符重排之后可以构成回文串。
此题令人疲劳的debug过程说明了,没事就不要在数组清零时的值赋成0或者-1,搞个-inf就可以了。。。
对于每个点,记录这个点到根的路径的每一个字符出现次数的奇偶性,这里用状态压缩存储在数组con[i]里。两个点之间的路径如果满足题目要求,那么必定con[i]=con[j]或者con[i]与con[j]二进制下只有一位不同。先dfs,如果路径不经过当前dfs到的点,可以通过DP得到答案。如果经过,使用树上启发式合并的方法,对每个二进制状态记录此时更新到的最大深度。由于是启发式合并,每个点的重链已经统计过,对于剩下的每条轻链先扫一遍,看里面的点能否和已经扫到的点配对,再更新这条轻链上的点的状态。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=500005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
int head[maxn],size[maxn],son[maxn],ans[maxn];
int con[maxn],dep[maxn];
int mxd[5000005];
bool visit[maxn],big[maxn];
int num=0,tot=0,odd=0;
struct Edge {
int from,to,pre,dist;
};
Edge edge[maxn*2];
void addedge(int from, int to,int dist) {
edge[num]=(Edge){from,to,head[from],dist};
head[from]=num++;
edge[num]=(Edge){to,from,head[to],dist};
head[to]=num++;
}
int dfs2(int now,int r,int step) {
visit[now]=1;son[now]=-1;size[now]=1;
con[now]=r;dep[now]=step;
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (!visit[to]) {
size[now]+=dfs2(to,r^(1<<edge[i].dist),step+1);
if (son[now]==-1||size[to]>size[son[now]]) son[now]=to;
}
}
if (son[now]!=-1) big[son[now]]=1;
return size[now];
}
int findmax(int now,int fa) {
int ans=mxd[con[now]];
for (int i=0;i<22;i++) ans=max(ans,mxd[con[now]^(1<<i)]);
if (ans>0) ans+=dep[now];
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (to!=fa&&!big[to]) ans=max(ans,findmax(to,now));
}
return ans;
}
void add(int now,int fa) {
mxd[con[now]]=max(mxd[con[now]],dep[now]);
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (to!=fa&&!big[to]) add(to,now);
}
}
void eliminate(int now,int fa) {
mxd[con[now]]=-inf;
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (to!=fa&&!big[to]) eliminate(to,now);
}
}
void dfs(int now,int fa,bool rem) {
int mx=0;
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (to!=fa&&!big[to]) dfs(to,now,0),mx=max(mx,ans[to]);
}
if (son[now]!=-1) dfs(son[now],now,1),mx=max(mx,ans[son[now]]);
ans[now]=mx;
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (to!=fa&&!big[to]) {
ans[now]=max(ans[now],findmax(to,now)-2*dep[now]);
add(to,now);
}
}
for (int i=0;i<22;i++)
ans[now]=max(ans[now],mxd[con[now]^(1<<i)]-dep[now]);
ans[now]=max(ans[now],mxd[con[now]]-dep[now]);
mxd[con[now]]=max(mxd[con[now]],dep[now]);
if (son[now]!=-1) big[son[now]]=0;
if (!rem) eliminate(now,fa);
}
int main() {
memset(head,-1,sizeof(head));
int n,i,j,x;
char c;
scanf("%d",&n);
for (i=2;i<=n;i++) {
scanf("%d %c",&x,&c);
addedge(i,x,c-'a');
}
mem0(big);mem0(visit);
dfs2(1,0,0);
mem0(ans);
dfs(1,0,0);
for (i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}