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 1 through 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.
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.
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.
4
1 s
2 a
3 s
3 1 1 0
5
1 a
2 h
1 a
4 h
4 1 0 1 0
题目大意:一棵树,每条边上有一个字符,问每个点的子树中最长的合法路径长度。所谓的合法路径长度就是给路径中的所有字符重新组合后可以是回文串。
分析:显然的dsu on the tree,不带修改操作,又只涉及到子树查询,只是细节比较麻烦.
满足要求的路径就是至多只有一个出现奇数次数字符,因为字符只可能是a ~ v,共22个字符,所以可以用二进制数存状态,0/1表示出现了偶数次/奇数次. s[i]表示1到i号点的路径的状态. f[i]表示状态为i的点的最深深度,h[i]表示i号点的深度.
考虑路径有哪些情况:不经过当前根节点的路径和经过当前根节点的路径,不经过当前根节点的路径在递归处理子节点的时候可以顺便处理完,经过当前根节点的有两种:一端恰好是根节点;两端在不同的子树内.前一种要特殊判断一下,后面一种的处理将修改和查询的顺序变一下:先查询,后修改.那么就能避免统计到同一子树内的答案.因为同一子树内的答案已经包含在前面的讨论的情况中了:不经过根节点和只有一端是根节点.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 500010; int head[maxn],nextt[maxn * 2],to[maxn * 2],tot = 1,a[maxn],n,s[maxn],h[maxn]; int sizee[maxn],son[maxn],ans[maxn],vis[maxn],f[maxn * 20],inf; void add(int x,int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void dfs1(int u,int fa) { h[u] = h[fa] + 1; if (u != 1) s[u] = s[fa] ^ (1 << a[u]); sizee[u] = 1; for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (v == fa) continue; dfs1(v,u); sizee[u] += sizee[v]; if(sizee[v] > sizee[son[u]]) son[u] = v; } } void cal(int u,int fa,int root) { ans[root] = max(ans[root],h[u] + f[s[u]] - 2 * h[root]); if ((s[u] ^ s[root]) == 0) ans[root] = max(ans[root],h[u] - h[root]); for (int i = 0; i < 22; i++) { int temp = s[u] ^ (1 << i); ans[root] = max(ans[root],h[u] + f[temp] - 2 * h[root]); if ((s[u] ^ s[root]) == (1 << i)) ans[root] = max(ans[root],h[u] - h[root]); } for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa) continue; cal(v,u,root); } } void update(int u,int fa,int flag) { if (flag) f[s[u]] = max(f[s[u]],h[u]); else f[s[u]] = inf; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa) continue; update(v,u,flag); } } void dfs2(int u,int fa,int flag) { for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa || v == son[u]) continue; dfs2(v,u,0); } if (son[u]) dfs2(son[u],u,1); int temp = s[u]; ans[u] = max(ans[u],f[temp] - h[u]); for (int i = 0; i < 22; i++) { temp = s[u] ^ (1 << i); ans[u] = max(ans[u],f[temp] - h[u]); } for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa || v == son[u]) continue; cal(v,u,u); update(v,u,1); } if (!flag) { for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa) continue; update(v,u,0); } f[s[u]] = inf; } else f[s[u]] = max(f[s[u]],h[u]); } void dfs3(int u,int fa) { for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (v == fa) continue; dfs3(v,u); ans[u] = max(ans[u],ans[v]); } } int main() { memset(f,128,sizeof(f)); inf = f[0]; scanf("%d",&n); for (int i = 2; i <= n; i++) { int fa; char ch[2]; scanf("%d",&fa); scanf("%s",ch); a[i] = ch[0] - 'a'; add(fa,i); add(i,fa); } dfs1(1,0); dfs2(1,0,1); dfs3(1,0); for (int i = 1; i <= n; i++) printf("%d ",ans[i]); printf(" "); return 0; }