CF741D
CF741D
题意:
给定一棵以 \(1\) 为根的数,每条边的边权是一个字母(a-v 共22种),求所有子树的最长 Dokhtar-kosh 路径。
Dokhtar-kosh 路径定义为存在一种重排方案使得重新排列后是一个回文串。
\(n \le 5 \times 10^5\)。
分析:
100紫祭。
不难发现,对于一个 Dokhtar-kosh 路径,它的充要条件为最多有一个字母的出现次数为奇数。
由于字母的种类为 \(22\) 种,考虑把一条路径的所有字母的奇偶性压到一个二进制数上。
由于异或运算的性质与奇偶性完全一致(偶+偶=偶,奇+偶=奇)。
记 \(dis_x\) 表示 \(x\) 到根节点这条路径的所有字母的奇偶性。
那么 \(u\) 到 \(v\) 这条路径的奇偶性为 \(dis_u \oplus dis_v\)。
一个合法的奇偶性有 \(23\) 种(加上全部偶数)。记为 \(h_i\)。
此时得到了一个时间复杂度为 \(O(23n^2)\) 的做法:枚举每个子树的根节点,计算出一个桶,\(f_x=\max(dep_t)\),且 \(dis_t=x\)。再枚举一个点 \(u\),那么 \(ans[root]=\max(f[dis[u] \oplus h_i])\)。注意要一个子树一个子树地走,并特判链的情况。
不过计算这个桶可以使用树上启发式合并。
时间复杂度为 \(O(23n \log n)\)。
代码:
#include<bits/stdc++.h>
#define N 500005
using namespace std;
int n;
struct edge{
int to;
char w;
};
vector<edge>p[N];
int ans[N], siz[N], dfn[N], son[N], dep[N], sum[N], cnt, h[30], tot, f[9000006], b[N];
void dfs1(int x, int fa) {
dep[x] = dep[fa] + 1;
dfn[x] = ++cnt;
b[cnt] = x;
siz[x] = 1;
int Maxson = 0;
for(int i = 0; i < p[x].size(); i++) {
int y = p[x][i].to;
if(y == fa) continue;
sum[y] = sum[x] ^ (1 << (p[x][i].w - 'a'));
dfs1(y, x);
siz[x] += siz[y];
if(siz[y] > Maxson) {
Maxson = siz[y];
son[x] = y;
}
}
}
void dfs2(int x, int fa, bool opt) {
for(int i = 0; i < p[x].size(); i++) {
int y = p[x][i].to;
if(y == fa || y == son[x]) continue;
dfs2(y, x, 1);
ans[x] = max(ans[x], ans[y]);
}
if(son[x]) dfs2(son[x], x, 0), ans[x] = max(ans[x], ans[son[x]]);
for(int i = 0; i < p[x].size(); i++) {
int y = p[x][i].to;
if(y == fa || y == son[x]) continue;
for(int l = dfn[y]; l <= dfn[y] + siz[y] - 1; l++) {
for(int u = 1; u <= 23; u++) if(f[sum[b[l]] ^ h[u]] > 0) ans[x] = max(ans[x], f[sum[b[l]] ^ h[u]] + dep[b[l]] - 2 * dep[x]);
}
for(int l = dfn[y]; l <= dfn[y] + siz[y] - 1; l++) f[sum[b[l]]] = max(f[sum[b[l]]], dep[b[l]]);
}
f[sum[x]] = max(f[sum[x]], dep[x]);
for(int i = 1; i <= 23; i++) { //处理一条链下来的情况
if(f[sum[x] ^ h[i]] > 0) ans[x] = max(ans[x], f[sum[x] ^ h[i]] - dep[x]);
}
if(opt) for(int l = dfn[x]; l <= dfn[x] + siz[x] - 1; l++) f[sum[b[l]]] = 0;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 2, fa; i <= n; i++) {
char c;
cin >> fa >> c;
p[i].push_back((edge){fa, c});
p[fa].push_back((edge){i, c});
}
h[++tot] = 0; for(int i = 0; i < 22; i++) h[++tot] = (1 << i);
dfs1(1, 0);
dfs2(1, 0, 1);
for(int i = 1; i <= n; i++) cout << ans[i] << " ";
return 0;
}
/*
2
1 a
*/
/*
5
1 a
2 b
1 c
4 d
*/