题意
传送门 Codeforces 914E Palindromes in a Tree
题解
一个字符串存在一个回文串排列,当且仅当字符串中出现次数为奇数的字符不超过一个。以 v v v 为根, a u a_u au 代表根到节点 u u u 间字母的奇偶性,则通过 v v v 的路径 u → w u\rightarrow w u→w 可以表为 a u ⊕ a w ⊕ a v a_u\oplus a_w\oplus a_v au⊕aw⊕av。
考虑点分治。每次处理仅考虑通过重心的路径。对于重心,依次考虑子树贡献。对于非重心 u u u,这样的路径的一个端点必然在 u u u 的子树内,递归相加即可。总时间复杂度 O ( 20 n log n ) O(20n\log n) O(20nlogn)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int C = 20;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<vector<int>> g(n);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
--u, --v;
g[u].push_back(v);
g[v].push_back(u);
}
string s;
cin >> s;
vector<int> a(n), b(n);
for (int i = 0; i < n; ++i) {
a[i] = 1 << (s[i] - 'a');
}
vector<int> sz(n), del(n);
vector<int> cnt(1 << C);
vector<ll> res(n, 1);
function<void(int)> solve = [&](int v) {
function<void(int, int)> get_sz = [&](int v, int p) {
sz[v] = 1;
for (int u : g[v]) {
if (u == p || del[u]) {
continue;
}
get_sz(u, v);
sz[v] += sz[u];
}
};
get_sz(v, -1);
for (int lim = sz[v] / 2;;) {
int mv = 0;
for (int u : g[v]) {
if (!del[u] && sz[u] < sz[v] && sz[u] > lim) {
mv = 1;
v = u;
break;
}
}
if (!mv) {
break;
}
}
function<void(int, int)> get_b = [&](int v, int p) {
for (int u : g[v]) {
if (del[u] || u == p) {
continue;
}
b[u] = b[v] ^ a[u];
get_b(u, v);
}
};
b[v] = a[v];
get_b(v, -1);
function<void(int, int, int)> add = [&](int v, int p, int d) {
cnt[b[v]] += d;
for (int u : g[v]) {
if (del[u] || u == p) {
continue;
}
add(u, v, d);
}
};
auto get = [&](int x) {
ll t = cnt[x];
for (int i = 0; i < C; ++i) {
t += cnt[x ^ (1 << i)];
}
return t;
};
function<ll(int, int, int)> count = [&](int v, int p, int d) {
ll t = get(b[v] ^ d);
for (int u : g[v]) {
if (del[u] || u == p) {
continue;
}
t += count(u, v, d);
}
res[v] += t;
return t;
};
add(v, -1, 1);
ll t = 0;
for (int u : g[v]) {
if (del[u]) {
continue;
}
add(u, v, -1);
t += count(u, v, b[v]);
add(u, v, 1);
}
cnt[b[v]] -= 1;
t += get(0);
res[v] += t / 2;
cnt[b[v]] += 1;
add(v, -1, -1);
del[v] = 1;
for (int u : g[v]) {
if (del[u]) {
continue;
}
solve(u);
}
};
solve(0);
for (int i = 0; i < n; ++i) {
cout << res[i] << " \n"[i + 1 == n];
}
return 0;
}