Description
Solution
将字符串的路径看做二进制数,那么一个路径上的字符能重新调整成回文串的充要条件是从根到两个点的二进制数异或和为(0)或者(2)的幂。这是因为在一个回文串里,出现次数为奇数的字符只能有一个或者没有。
那么问题现在变成(x)的子树里找最大的(dep_a + dep_b - dep_{lca(a, b)})。我们可以考虑钦定两个点的(lca)为(x),最后用(x)的子树的值更新它即可。
这样我们就有了(dsu on tree)的思路。那么如何保证两个点的(lca)就是(x)点呢?只需要一条链一条链的进行处理,这样任意两点的(lca)必然就是(x)。将二进制数为(s)的最深深度记录下来,枚举一下二进制数互相异或得到的值就行了。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 500000;
int head[N + 50], num, a[N + 50], n, siz[N + 50], dep[N + 50], ans[N + 50], maxson[N + 50], s[N + 50], maxv, f[N * 20], inf;
struct Node
{
int next, to;
} edge[N + 50];
void Addedge(int u, int v)
{
edge[++num] = (Node){head[u], v};
head[u] = num;
return;
}
void Dfs1(int x, int fa)
{
siz[x] = 1; dep[x] = dep[fa] + 1;
if (x != 1) s[x] = s[fa] ^ (1 << a[x]);
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
Dfs1(v, x);
siz[x] += siz[v];
if (siz[v] > siz[maxson[x]]) maxson[x] = v;
}
return;
}
void Calc(int rt, int x)
{
int now = s[x];
maxv = max(maxv, f[now] + dep[x] - 2 * dep[rt]);
if ((s[x] ^ s[rt]) == 0) maxv = max(maxv, dep[x] - dep[rt]);
for (int i = 0; i < 22; i++)
{
now = (1 << i) ^ s[x];
maxv = max(maxv, f[now] + dep[x] - 2 * dep[rt]);
if ((s[x] ^ s[rt]) == (1 << i)) maxv = max(maxv, dep[x] - dep[rt]);
}
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
Calc(rt, v);
}
return;
}
void Change(int x, int k)
{
if (k) f[s[x]] = max(f[s[x]], dep[x]);
else f[s[x]] = inf;
for (int i = head[x]; i; i = edge[i].next) Change(edge[i].to, k);
return;
}
void Dfs2(int x, int remain)
{
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (v == maxson[x]) continue;
Dfs2(v, 0);
}
if (maxson[x]) Dfs2(maxson[x], 1);
maxv = 0; int now = s[x];
maxv = max(maxv, f[now] - dep[x]);
for (int i = 0; i < 22; i++)
{
now = (1 << i) ^ s[x];
maxv = max(maxv, f[now] - dep[x]);
}
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (v == maxson[x]) continue;
Calc(x, v); Change(v, 1);
}
ans[x] = maxv;
if (!remain)
{
for(int i = head[x]; i; i = edge[i].next)
Change(edge[i].to, 0);
f[s[x]] = inf;
}
else f[s[x]] = max(f[s[x]], dep[x]);
return;
}
void Erase(int x)
{
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to; Erase(v);
ans[x] = max(ans[x], ans[v]);
}
return;
}
int main()
{
scanf("%d", &n);
char tmp;
for (int i = 2, fa; i <= n; i++)
{
scanf("%d", &fa);
cin >> tmp;
Addedge(fa, i); a[i] = tmp - 'a';
}
Dfs1(1, 0);
memset(f, 128, sizeof(f)); inf = f[0];
Dfs2(1, 0);
Erase(1);
for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
return 0;
}