Codeforces Round #383 (Div. 1): D. Arpa’s letter-marked tree…(dsu on tree+状压)

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/83826537

题意:

给你一棵n个节点的树,每条边都代表着一个字母(a~v),对于每个节点u,求出以u为根的子树中有多少条路径满足:路径上的字符重新排列后可以得到一个回文字符串

思路:

前置:dsu on tree

然后就可以思考该怎么O(n²)暴力了

因为只有22个字母,所以可以用一个数字代表当前哪些字母出现了奇数次,如果字典序第i个字母出现奇数次,那么第i位就为1,否则就为0,这样的话只要求出val[u]表示从u点到根的路径状态,如果val[u]^val[v]==0 或者val[u]^val[v]的二进制中只有1位是1,那么路径u到v就可以重排形成回文字符串

#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
vector<int> G[500005];
int val[4233333], dp[4233333];
int dep[500005], siz[500005], hson[500005], ans[500005];
void Sech1(int u, int p)
{
	int i, v;
	val[u] ^= val[p];
	siz[u] = 1, dep[u] = dep[p]+1;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==p)
			continue;
		Sech1(v, u);
		siz[u] += siz[v];
		if(siz[v]>siz[hson[u]])
			hson[u] = v;
	}
}
void Init(int u)
{
	int i, v;
	dp[val[u]] = -1044266558;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		Init(v);
	}
}
void Update(int u)
{
	int i, v;
	dp[val[u]] = max(dp[val[u]], dep[u]);
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		Update(v);
	}
}
void Gao(int u, int now)
{
	int i, v;
	ans[now] = max(ans[now], dep[u]+dp[val[u]]);
	for(i=0;i<=21;i++)
		ans[now] = max(ans[now], dep[u]+dp[val[u]^(1<<i)]);
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		Gao(v, now);
	}
}
void Sech2(int u)
{
	int i, v;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==hson[u])
			continue;
		Sech2(v);
		Init(v);
	}
	if(hson[u])
		Sech2(hson[u]);
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==hson[u])
			continue;
		Gao(v, u), Update(v);
	}
	dp[val[u]] = max(dp[val[u]], dep[u]);
	ans[u] = max(ans[u], dep[u]+dp[val[u]]);
	for(i=0;i<=21;i++)
		ans[u] = max(ans[u], dep[u]+dp[val[u]^(1<<i)]);
	ans[u] -= dep[u]*2;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		ans[u] = max(ans[u], ans[v]);
	}
}
int main(void)
{
	char ch;
	int n, i, x;
	scanf("%d", &n);
	for(i=2;i<=n;i++)
	{
		scanf("%d %c", &x, &ch);
		G[x].push_back(i);
		val[i] = 1<<(ch-'a');
	}
	memset(dp, -62, sizeof(dp));
	Sech1(1, 0);
	Sech2(1);
	for(i=1;i<=n;i++)
		printf("%d ", ans[i]);
	puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/83826537