zoukankan      html  css  js  c++  java
  • BZOJ1864: [Zjoi2006]三色二叉树

    BZOJ1864: [Zjoi2006]三色二叉树

    Description

    Input

    仅有一行,不超过500000个字符,表示一个二叉树序列。

    Output

    输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

    Sample Input

    1122002010

    Sample Output

    5 2

    题解Here!

    很明显,一道树形$DP$。

    首先,那个序列转换成树,应该没有什么问题,一发$DFS$搞定。

    然后就是在树上$DP$。

    那个最大最小值先不管它,对于一种情况讨论,另外一种情况同理即可。

    先看最大值:

    设$dp[i][0/1/2]$表示对于$i$的子树,$i$涂绿色$0$,红色$1$,蓝色$2$,所能达到的最多的绿色节点个数。

    然后对于$i$的儿子个数$num[i]$开始特判:

    • $num[i]==0$:

    这个说明$i$为叶子节点,直接$dp[i][0]=1;dp[i][1]=dp[i][2]=0;$即可。

    • $num[i]==1$:

    只有一个儿子也很好办,分类讨论儿子涂什么颜色即可:

    $$dp[i][0]=maxleft{egin{array}{}dp[j][1]+1\dp[j][2]+1end{array} ight.jin son_i$$

    $$dp[i][1/2]=maxleft{egin{array}{}dp[j][0]\dp[j][2/1]end{array} ight.jin son_i$$

    注:斜杠表示两种方案只选一种,并且不同的两个斜杠表示的四个决策是两两对应的。

    • $num[i]==2$:

    额,这个就稍微有点烦人了,但是还是很好想:

    $$dp[i][0]=maxleft{egin{array}{}maxleft{egin{array}{}dp[j_1][1]+1\dp[j_2][2]+1end{array} ight.\\maxleft{egin{array}{}dp[j_1][2]+1\dp[j_2][1]+1end{array} ight.end{array} ight.$$

    $$dp[i][1/2]=maxleft{egin{array}{}maxleft{egin{array}{}dp[j_1][0]\dp[j_2][2/1]end{array} ight.\\maxleft{egin{array}{}dp[j_1][2/1]\dp[j_2][0]end{array} ight.end{array} ight.$$

    其中$j_1,j_2in son_i$。

    然后就是$DFS$一遍就可以出解了。

    最后答案就是:$$maxleft{egin{array}{}dp[1][0]\dp[1][1]\dp[1][2]end{array} ight.$$

    这只对于最大值,最小值同理。

    记得最小值开始时要赋为$+infty$。

    本蒟蒻表示$1A$很高兴!

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define MAXN 500010
    using namespace std;
    int n=1,c=1,pos=1;
    int head[MAXN],num[MAXN],f[MAXN][3],g[MAXN][3];
    struct Tree{
    	int next,to;
    }a[MAXN<<1];
    char str[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void add(int x,int y){
    	a[c].to=y;a[c].next=head[x];head[x]=c++;
    }
    void dfs(int rt){
    	num[rt]=str[pos]-'0';
    	for(int i=1;i<=num[rt];i++){
    		n++;
    		add(rt,n);
    		pos++;
    		dfs(n);
    	}
    }
    void dp(int rt){
    	if(num[rt]==0){
    		f[rt][0]=g[rt][0]=1;
    		f[rt][1]=f[rt][2]=g[rt][1]=g[rt][2]=0;
    	}
    	else if(num[rt]==1){
    		int will;
    		for(int i=head[rt];i;i=a[i].next){
    			will=a[i].to;
    			dp(will);
    			f[rt][0]=max(f[rt][0],max(f[will][1],f[will][2])+1);
    			f[rt][1]=max(f[rt][1],max(f[will][0],f[will][2]));
    			f[rt][2]=max(f[rt][2],max(f[will][0],f[will][1]));
    			g[rt][0]=min(g[rt][0],min(g[will][1],g[will][2])+1);
    			g[rt][1]=min(g[rt][1],min(g[will][0],g[will][2]));
    			g[rt][2]=min(g[rt][2],min(g[will][0],g[will][1]));
    		}
    	}
    	else{
    		int will,son[2];
    		for(int i=head[rt],j=0;i;i=a[i].next,j++){
    			will=a[i].to;
    			son[j]=will;
    			dp(will);
    		}
    		f[rt][0]=max(f[rt][0],max(f[son[0]][1]+f[son[1]][2],f[son[0]][2]+f[son[1]][1])+1);
    		f[rt][1]=max(f[rt][1],max(f[son[0]][0]+f[son[1]][2],f[son[0]][2]+f[son[1]][0]));
    		f[rt][2]=max(f[rt][2],max(f[son[0]][0]+f[son[1]][1],f[son[0]][1]+f[son[1]][0]));
    		g[rt][0]=min(g[rt][0],min(g[son[0]][1]+g[son[1]][2],g[son[0]][2]+g[son[1]][1])+1);
    		g[rt][1]=min(g[rt][1],min(g[son[0]][0]+g[son[1]][2],g[son[0]][2]+g[son[1]][0]));
    		g[rt][2]=min(g[rt][2],min(g[son[0]][0]+g[son[1]][1],g[son[0]][1]+g[son[1]][0]));
    	}
    }
    void work(){
    	scanf("%s",str+1);
    	dfs(1);
    	memset(f,0,sizeof(f));
    	memset(g,127,sizeof(g));
    	dp(1);
    	printf("%d %d
    ",max(f[1][0],max(f[1][1],f[1][2])),min(g[1][0],min(g[1][1],g[1][2])));
    }
    int main(){
    	work();
    	return 0;
    }
    
  • 相关阅读:
    今日大跌!
    web servers
    ASP.NET2.0缓存机制
    赚钱的总是史玉柱?
    asp.net速查手册
    为伊消得人憔悴,我的2007成就难有,内心彷徨
    success
    失守4600点
    Linux下chkconfig命令详解
    FTP批处理下载木马
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9937429.html
Copyright © 2011-2022 走看看