题目大意:(来源 : https://www.luogu.org/problem/CF741D)
若排序后能变成一个回文串,则路径上最多只有一个字符出现奇数次,用0 1 表示每个字符出现是奇还是偶。
dfs预处理每个点到根节点的所有字符出现状态 和 距离。当前点 为 i 时,最长路径要么经过 i,要么在 i 的子树中, 后者是一个子问题,可以用 dp 记录一下。
考虑经过 i 的最长路径怎么解决:
一个点能和另外一个点组成 Dokhtar-kosh 路径,当且仅当两个点的状态最多只有一位不同。
由于之前预处理了每个点到根节点的状态,根据异或的性质,相同部分异或两次会抵消,i 的两个来自不同的子树的结点状态相异或得到的恰好是两点间经过 i 点的简单路径的状态。
因此可以 维护一个数组:ans[i] 表示状态到根节点的字符出现状态为 i,到根节点的最大距离。暴力搜索 i 的每一棵子树,对当前子树的每一个点,枚举可以组合的状态点更新答案,搜索完一棵子树后再将该子树的状态维护到 a n s ans ans 数组中。
复杂度: O ( 22 ∗ n log n ) O(22 *n\log n) O(22∗nlogn)
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
const int maxn = 1e6 + 10;
const int inf = -0x3f3f3f3f;
int state[maxn],deep[maxn];
vector<pii> g[maxn];
int dp[maxn],n,son[maxn],f[maxn],fa[maxn];
int ans[1 << 23];
void dfs(int u) {
son[u] = 0;f[u] = 1;
for(auto it : g[u]) {
deep[it.fir] = deep[u] + 1;
state[it.fir] = state[u] ^ (1 << it.sec);
fa[it.fir] = u;
dfs(it.fir);
f[u] += f[it.fir];
if(!son[u] || f[son[u]] < f[it.fir]) son[u] = it.fir;
}
}
void clear(int u) {
ans[state[u]] = inf;
for(auto it : g[u])
clear(it.fir);
}
void upd(int u) {
ans[state[u]] = max(ans[state[u]],deep[u]);
for(auto it : g[u])
upd(it.fir);
}
int qry(int u,int rt) {
int mx = 0;
mx = max(mx,ans[state[u]] + deep[u] - 2 * deep[rt]);
for(int i = 0; i < 22; i++) {
int p = state[u] ^ (1 << i);
if(ans[p] != -1)
mx = max(mx,ans[p] + deep[u] - 2 * deep[rt]);
}
for(auto it : g[u])
mx = max(qry(it.fir,rt),mx);
return mx;
}
void dfs2(int u,int keep) {
dp[u] = 0;
for(auto it : g[u])
if(it.fir != son[u]) dfs2(it.fir,0);
if(son[u]) dfs2(son[u],1);
for(auto it : g[u]) {
dp[u] = max(dp[u],dp[it.fir]);
if(it.fir == son[u]) continue;
dp[u] = max(dp[u],qry(it.fir,u));
upd(it.fir);
}
dp[u] = max(dp[u],ans[state[u]] - deep[u]);
for(int i = 0; i < 22; i++) {
int p = state[u] ^ (1 << i);
dp[u] = max(dp[u],ans[p] - deep[u]);
}
ans[state[u]] = max(ans[state[u]],deep[u]);
if(!keep) clear(u);
}
int main() {
memset(ans,inf,sizeof ans);
scanf("%d",&n);
for(int i = 2; i <= n; i++) {
int v;char s[2];
scanf("%d%s",&v,s);
int q = s[0] - 'a';
g[v].push_back(pii(i,q));
}
deep[1] = 0;fa[1] = 0;
dfs(1);dfs2(1,0);
for(int i = 1; i <= n; i++) {
if(i - 1) printf(" ");
printf("%d",dp[i]);
}
return 0;
}