bzoj 1864 三色二叉树
Description
Input
仅有一行,不超过500000个字符,表示一个二叉树序列。
Output
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
Sample Input
1122002010
Sample Output
5 2
HINT
Source
思路: 本题是树型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 }