您的位置:首页 > 其它

Codeforces 741D D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 树上启发式合并

2017-11-26 21:16 731 查看
D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

time limit per test
3 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

Just in case somebody missed it: we have wonderful girls in Arpa’s land.

Arpa has a rooted tree (connected acyclic graph) consisting of n vertices. The vertices are numbered 1through n,
the vertex 1 is the root. There is a letter written on each edge of this tree. Mehrdad is a fan of Dokhtar-kosh things.
He call a string Dokhtar-kosh, if we can shuffle the characters in string such that it becomes palindrome.



He asks Arpa, for each vertex v, what is the length of the longest simple path in subtree of v that
form a Dokhtar-kosh string.

Input

The first line contains integer n (1  ≤  n  ≤  5·105) —
the number of vertices in the tree.

(n  -  1) lines follow, the i-th
of them contain an integer pi + 1 and
a letter ci + 1 (1  ≤  pi + 1  ≤  i, ci + 1 is
lowercase English letter, between a and v, inclusively), that mean that there is an edge between
nodes pi + 1 and i + 1 and
there is a letter ci + 1 written
on this edge.

Output

Print n integers. The i-th
of them should be the length of the longest simple path in subtree of the i-th vertex that form a Dokhtar-kosh string.

Examples

input
4
1 s
2 a
3 s


output
3 1 1 0


input
5
1 a
2 h
1 a
4 h


output
4 1 0 1 0


<
fe3a
span style="font-size:18px;">

一棵树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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐