bzoj 1864 三色二叉树

Description

Input

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

Output

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

Sample Input

1122002010

Sample Output

5 2

HINT

 

Source

Day1

 

思路: 本题是树型dp,题目给出的字符序列刚好可以递归构造二叉树。 

然后用f[x][0],g[x][0]分别表示当x涂成绿色的时候这个子树绿色的点最多和最少的数量。  

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define re register
 4 #define R  re int
 5 #define rep(i,a,b) for(R i=a;i<=b;i++)
 6 #define Rep(i,a,b) for(R i=a;i>=b;i--)
 7 #define ms(i,a)    memset(a,i,sizeof(a))
 8 #define lc         ch[x][0]
 9 #define rc         ch[x][1]
10 template<class T>void read(T &x){
11   x=0; char c=0;
12   while (!isdigit(c)) c=getchar();
13   while (isdigit(c)) x=x*10+(c^48),c=getchar();
14 }
15 int const N=500001;
16 int const inf=1e8;
17 int n,ch[N][2],f[N][3],sum,x,g[N][3];
18 char s[N];
19 void dfs(){
20   int t=++sum;
21   if(s[x]=='0') return;
22   if(s[x]=='1') ch[t][0]=sum+1,x++,dfs();
23   if(s[x]=='2'){
24     ch[t][0]=sum+1; x++;dfs();
25     ch[t][1]=sum+1; x++;dfs();
26   }
27 }
28 void solve(int x){
29   if(x==0) return ;
30   if(!lc){
31     f[x][0]=g[x][0]=1;  return;
32   }
33   solve(lc); solve(rc);
34   if(!rc){
35     f[x][0]=1+max(f[lc][1],f[lc][2]);
36     f[x][1]=max(f[lc][0],f[lc][2]);
37     f[x][2]=max(f[lc][0],f[lc][1]);
38     g[x][0]=1+min(g[lc][1],g[lc][2]);
39     g[x][1]=min(g[lc][0],g[lc][2]);
40     g[x][2]=min(g[lc][0],g[lc][1]);
41   }else {
42     f[x][0]=1+max(f[lc][1]+f[rc][2],f[lc][2]+f[rc][1]);
43     f[x][1]=max(f[lc][0]+f[rc][2],f[rc][0]+f[lc][2]);
44     f[x][2]=max(f[lc][0]+f[rc][1],f[rc][0]+f[lc][1]);
45     g[x][0]=1+min(g[lc][1]+g[rc][2],g[lc][2]+g[rc][1]);
46     g[x][1]=min(g[lc][0]+g[rc][2],g[rc][0]+g[lc][2]);
47     g[x][2]=min(g[lc][0]+g[rc][1],g[rc][0]+g[lc][1]);
48   }
49 }
50 int main(){
51   scanf("%s",s);
52   dfs();
53   solve(1);
54   printf("%d %d\n",max(f[1][0],max(f[1][1],f[1][2])),min(g[1][0],min(g[1][1],g[1][2])));
55   return 0;
56 }
View Code

 

posted @ 2018-12-28 10:38  zjxxcn  阅读(159)  评论(0编辑  收藏  举报