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

      

  • 相关阅读:
    关于ng路由的传参问题(传递一个,多个参数)
    ng指令控制一个元素的影藏的与显示几种方法的使用
    将一个对象push到数组之中的几点问题
    关于ng的路由的几点想法(ui-view)
    angularJS自定义一个过滤器
    ng自带的表单验证
    实现标签的添加与删除(tags)
    关于ng-class,ng-style的用法
    5分钟搞懂:session与cookie
    前端浏览器的两种缓存:协商缓存和强缓存
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6544558.html
Copyright © 2020-2023  润新知