zoukankan      html  css  js  c++  java
  • 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;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6544558.html
Copyright © 2011-2022 走看看