CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

II.II.CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

名字真长

假如它没有”在每个子树中最长“的限制,我们倒真可以点分治,然后就是水题了;但是它要求在每个子树中最长,怎么办呢?

直接上dsu on tree就行了。思想还是借鉴点分治,所有点对都在LCA处处理就行。先处理轻儿子子树并回撤,然后处理重儿子不回撤,然后加入自身及轻儿子影响。在加入一坨东西时,要先查看桶中是否有能与其配对成回文串的另一半(明显一共只有 (23) 种),然后再加,这是避免子树内部配对。都是点分治的老套路了,不必多说。

所以dsu on tree似乎能完美替代大部分点分治的题

代码:

#include<bits/stdc++.h>
using namespace std;
int n,msk[500100],fa[500100],son[500100],sz[500100],dep[500100],buc[1<<22],res[500100],ans;
char s[10];
vector<int>v[500100];
void dfs1(int x){
	sz[x]=1;
	for(auto y:v[x]){
		dep[y]=dep[x]+1,dfs1(y),sz[x]+=sz[y];
		if(sz[son[x]]<sz[y])son[x]=y;
	}
}
void dfsread(int x){
	if(buc[msk[x]]!=-1)ans=max(ans,dep[x]+buc[msk[x]]);
	for(int i=0;i<22;i++)if(buc[msk[x]^(1<<i)]!=-1)ans=max(ans,dep[x]+buc[msk[x]^(1<<i)]);
	for(auto y:v[x])dfsread(y);
}
void dfswrite(int x){
	buc[msk[x]]=max(buc[msk[x]],dep[x]);
	for(auto y:v[x])dfswrite(y);
}
void dfserase(int x){
	buc[msk[x]]=-1;
	for(auto y:v[x])dfserase(y);
}
void dsuontree(int x){
	for(auto y:v[x])if(y!=son[x])dsuontree(y),dfserase(y);
	if(son[x])dsuontree(son[x]);
	ans=0;
	buc[msk[x]]=max(buc[msk[x]],dep[x]);
	if(buc[msk[x]]!=-1)ans=max(ans,dep[x]+buc[msk[x]]);
	for(int i=0;i<22;i++)if(buc[msk[x]^(1<<i)]!=-1)ans=max(ans,dep[x]+buc[msk[x]^(1<<i)]);
	for(auto y:v[x])if(y!=son[x])dfsread(y),dfswrite(y);
	res[x]=ans-2*dep[x];
	for(auto y:v[x])res[x]=max(res[x],res[y]);
}
int main(){
	scanf("%d",&n),memset(buc,-1,sizeof(buc));
	for(int i=2;i<=n;i++)scanf("%d%s",&fa[i],s),msk[i]=msk[fa[i]]^(1<<(s[0]-'a')),v[fa[i]].push_back(i);
	dfs1(1);
	dsuontree(1);
	for(int i=1;i<=n;i++)printf("%d ",res[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/Troverld/p/14637052.html