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

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:CF741D

正解:$dsu$ $on$ $tree$

解题报告:

  对于这种回文串的问题,很显然出现次数为奇数的个数$<=1$,那么这个状态就可以状压了。

  用$S$表示从这个点到根的字母奇偶性情况,因为$<=1$,我们特判掉$0$之后就只需要考虑有一位的情况,枚举这一位,可以唯一地得到一个状态,来满足条件,那么就可以做了。

  考虑处理一个节点时,首先可以顺便处理掉从根到子树内某个点的情况,然后我们只需要考虑子树内两个点组合而成的情况。

  用一个数组记一下每种状态的最大深度就$over$了…

  有一个小$trick$:必须要用子树中的最优值往上更新…

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
#include <bitset>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 500011;
const int MAXM = 1000011;
int n,father[MAXN],ecnt,first[MAXN],to[MAXM],next[MAXM],size[MAXN],son[MAXN],deep[MAXN],ans[MAXN],Max,s[MAXN],f[10000011]/*!!!数组开小了!!!*/,inf;
char ch[MAXN];
inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}

inline void dfs(int x,int fa){
	size[x]=1; if(fa) s[x]=s[fa]^(1<<(ch[x]-'a'));
	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; deep[v]=deep[x]+1;
		dfs(v,x); size[x]+=size[v];
		if(size[v]>size[son[x]]) son[x]=v;
	}
}

inline void calc(int rt,int x){
    int state=s[x];
    Max=max(Max,f[state]+deep[x]-2*deep[rt]);
    if ((s[x]^s[rt])==0) Max=max(Max,deep[x]-deep[rt]);
    for (int i=0;i<22;++i) {
        state=(1<<i)^s[x];
        Max=max(Max,f[state]+deep[x]-2*deep[rt]);
        if ((s[x]^s[rt])==(1<<i)) Max=max(Max,deep[x]-deep[rt]);
    }
    for (int i=first[x];i;i=next[i])
        calc(rt,to[i]);
}

inline void change(int x,int type){
	if(type) f[s[x]]=max(f[s[x]],deep[x]);
	else f[s[x]]=inf;

	for(int i=first[x];i;i=next[i])
		change(to[i],type);
}

inline void solve(int x,bool top){
	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; if(v==son[x]) continue;
		solve(v,1);
	}

	if(son[x])
		solve(son[x],0);

	Max=0; int S=s[x],nows;
	Max=max(Max,f[S]-deep[x]);
	for(int i=0;i<22;i++) {
		nows=(1<<i)^s[x];
		Max=max(Max,f[nows]-deep[x]);
	}

	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; if(v==son[x]) continue;
		calc(x,v);
		change(v,1);
	}

	ans[x]=Max;

	if(top) {
		for(int i=first[x];i;i=next[i])
			change(to[i],0);
		f[s[x]]=inf;
	}
	else f[s[x]]=max(f[s[x]],deep[x]);
}

inline void upd(int x){
	for(int i=first[x];i;i=next[i]) {
		upd(to[i]);
		ans[x]=max(ans[x],ans[to[i]]);
	}
}

inline void work(){
	n=getint(); for(int i=2;i<=n;i++) father[i]=getint(),link(father[i],i),scanf("%c",&ch[i]);
	deep[1]=0;
	dfs(1,0); memset(f,-0x7f,sizeof(f)); inf=f[0];
	solve(1,1);
	upd(1);
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
}

int main()
{
    work();
    return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

原文地址:https://www.cnblogs.com/ljh2000-jump/p/6544558.html