【CF741D】Arpa’s lettermarked tree and Mehrdad’s Dokhtarkosh paths

题目

题目链接:https://codeforces.ml/problemset/problem/741/D
一棵根为 \(1\) 的树,每条边上有一个字符( \(a\sim v\)\(22\) 种)。一条简单路径被称为 Dokhtar-kosh 当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的 Dokhtar-kosh 路径的长度。

思路

明显地要把一条路径之间所有字母状压,然后一条路径是 Dk 路径当且仅当状压后最多包含一个 \(1\)
\(a[x]\) 表示点 \(x\) 到根的路径中字母的状态,那么对于一条 \(u\)\(v\) 的路径,其状态就是 \(a[u]\operatorname{xor} a[v]\)
\(maxd[s]\) 表示当前搜索到的子树中状态为 \(s\) 的点最深的深度,每次计算答案的时候枚举状态为 \(1\) 的字母,乱搞即可。
直接上 dsu on tree。时间复杂度 \(O(nm\log n)\),其中 \(m\) 是字母数(即 \(22\))。

代码

#include <bits/stdc++.h>
using namespace std;

const int N=500010,M=(1<<22)+10;
int n,tot,head[N],a[N],son[N],size[N],maxd[M],dep[N],ans[N],dfn[N],id[N];
char ch[5];

struct edge
{
	int next,to;
}e[N];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void dfs1(int x,int fa)
{
	dep[x]=dep[fa]+1; size[x]=1;
	a[x]^=a[fa]; dfn[x]=++tot; id[tot]=x;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		dfs1(v,x);
		size[x]+=size[v];
		if (size[v]>size[son[x]]) son[x]=v;
	}
}

void update(int &WYCTQL,int v,int x,int p)
{
	if (maxd[v]) WYCTQL=max(WYCTQL,maxd[v]+dep[x]-2*dep[p]);
	for (int i=0;i<22;i++)
		if (maxd[v^(1<<i)]) WYCTQL=max(WYCTQL,maxd[v^(1<<i)]+dep[x]-2*dep[p]);
}

void dfs2(int x,bool clr)
{
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=son[x])
			dfs2(v,1),ans[x]=max(ans[x],ans[v]);
	}
	if (son[x])
	{
		dfs2(son[x],0);
		ans[x]=max(ans[x],ans[son[x]]);
	}
	update(ans[x],a[x],x,x);
	maxd[a[x]]=max(maxd[a[x]],dep[x]);
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=son[x])
		{
			for (int j=dfn[v];j<dfn[v]+size[v];j++)
				update(ans[x],a[id[j]],id[j],x);
			for (int j=dfn[v];j<dfn[v]+size[v];j++)
				maxd[a[id[j]]]=max(maxd[a[id[j]]],dep[id[j]]);
		}
	}
	if (clr)
		for (int i=dfn[x];i<dfn[x]+size[x];i++)
			maxd[a[id[i]]]=0;
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
	for (int i=2,x;i<=n;i++)
	{
		cin>>x>>ch;
		add(x,i);
		a[i]=1<<(ch[0]-'a');
	}
	tot=0;
	dfs1(1,0); dfs2(1,0);
	for (int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/13763925.html