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
*/
posted @ 2023-12-10 19:51  小超手123  阅读(33)  评论(0编辑  收藏  举报