题意:
给你一棵树,每条边有个字符,问对于每个节点,他的子树中最长的好路径是多长。
好定义为把路径中字符排列后可以变成回文。
题解:
路径可以成回文条件是出现次数为奇数的字符数量 <= 1。
对于每个点我们用二进制记录他到根节点路径的异或和d[i](把每个字符看成一位)。
那么任意路径出现的字符次数就是 d[i] ^ d[j] 。
现在要求每个子树,启发式合并即可。
还可以用预处理dfs序,这样每次edt就不用递归了,直接for循环,优化常数和可读性。
代码:
#include <bits/stdc++.h>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 5e5 + 5;
vector<pii> G[MAXN];
int d[MAXN];
int cnt[1<<22];
int siz[MAXN], son[MAXN], dep[MAXN];
void pre_dfs (int now, int par, int dd = 1) {
siz[now] = 1;
dep[now] = dd;
for (pii i : G[now]) {
d[i.fir] = d[now] ^ (1 << i.sec);
pre_dfs (i.fir, now, dd + 1);
if (siz[i.fir] > siz[son[now]]) son[now] = i.fir;
siz[now] += siz[i.fir];
}
}
int res[MAXN];
void edt (int now, int top) {
int v = d[now];
for (int i = 0; i < 22; i++) {
int o = v ^ (1<<i);
if (cnt[o]) res[top] = max(res[top], dep[now] - dep[top] * 2 + cnt[o]);
}
if (cnt[v]) res[top] = max(res[top], dep[now] - dep[top] * 2 + cnt[v]);
for (auto i : G[now]) {
edt(i.fir, top);
}
}
void add (int now) {
cnt[d[now]] = max(cnt[d[now]], dep[now]);
for (pii i : G[now]) add (i.fir);
}
void clr (int now) {
cnt[d[now]] = 0;
for (pii i : G[now]) {
clr (i.fir);
}
}
void dfs (int now, int par, int kep) {
for (auto i : G[now]) {
if (i.fir == par || i.fir == son[now]) continue;
dfs (i.fir, now, 0);
res[now] = max(res[now], res[i.fir]);
}
if (son[now]) dfs(son[now], now, 1), res[now] = max(res[now], res[son[now]]);;
if (cnt[d[now]]) res[now] = max(res[now], cnt[d[now]] - dep[now]);
for (int i = 0; i < 22; i++) {
int o = d[now] ^ (1 << i);
if (cnt[o])
res[now] = max(res[now], -dep[now] + cnt[o]);
}
// if (now == 2) debug(son[now])
cnt[d[now]] = max(cnt[d[now]], dep[now]);
for (auto i : G[now])
if (i.fir != son[now]) {
edt(i.fir, now);
add(i.fir);
}
if (!kep) clr (now);
}
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int n;
scanf ("%d", &n);
for (int i = 1; i < n; i++) {
char c[2];
int p;
scanf ("%d %s", &p, c);
G[p].pb (mp(i + 1, c[0] - 'a'));
}
pre_dfs(1, 0);
dfs(1, 0, 0);
for (int i = 1; i <= n; i++) printf ("%d ", res[i]);
return 0;
}