bzoj1864 三色二叉树
Description
Input
仅有一行,不超过500000个字符,表示一个二叉树序列。
Output
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
Sample Input
1122002010
Sample Output
5 2
树形dp
int mx[N][3][3]; //点i的颜色为0/1/2,点i为根的子树最多有多少个0/1/2
int mn[N][3][3]; //点i的颜色为0/1/2,点i为根的子树最少有多少个0/1/2
然后各种乱搞
(写的太挫辣。。。直接meta-programming是可以解决的。。。)
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <map> #include <set> #include <vector> #include <queue> #include <cmath> #include <cctype> #include <string> #include <cfloat> #include <stack> #include <cassert> #include <bitset> using namespace std; const int N = 500010; char str[N]; int ch[N][2], cnt, pos; int build() { if(str[pos] == 0) return 0; ++ cnt; int cur = cnt; int tmp = cnt; if(str[pos] == '0') { pos ++; } else if(str[pos] == '1') { pos ++; ch[cur][0] = build(); } else { pos ++; ch[cur][0] = build(); ch[cur][1] = build(); } return cur; } int mx[N][3][3]; //点i的颜色为0/1/2,点i为根的子树最多有多少个0/1/2 int mn[N][3][3]; //点i的颜色为0/1/2,点i为根的子树最少有多少个0/1/2 void dfs(int u) { int c1 = ch[u][0], c2 = ch[u][1]; if(c1 && c2) { //有两个儿子 dfs(c1); dfs(c2); mx[u][0][0] = max(mx[c1][1][0] + mx[c2][2][0], mx[c1][2][0] + mx[c2][1][0]) + 1; mx[u][0][1] = max(mx[c1][1][1] + mx[c2][2][1], mx[c1][2][1] + mx[c2][1][1]); mx[u][0][2] = max(mx[c1][1][2] + mx[c2][2][2], mx[c1][2][2] + mx[c2][1][2]); mx[u][1][0] = max(mx[c1][0][0] + mx[c2][2][0], mx[c1][2][0] + mx[c2][0][0]); mx[u][1][1] = max(mx[c1][0][1] + mx[c2][2][1], mx[c1][2][1] + mx[c2][0][1]) + 1; mx[u][1][2] = max(mx[c1][0][2] + mx[c2][2][2], mx[c1][2][2] + mx[c2][0][2]); mx[u][2][0] = max(mx[c1][0][0] + mx[c2][1][0], mx[c1][1][0] + mx[c2][0][0]); mx[u][2][1] = max(mx[c1][0][1] + mx[c2][1][1], mx[c1][1][1] + mx[c2][0][1]); mx[u][2][2] = max(mx[c1][0][2] + mx[c2][1][2], mx[c1][1][2] + mx[c2][0][2]) + 1; mn[u][0][0] = min(mn[c1][1][0] + mn[c2][2][0], mn[c1][2][0] + mn[c2][1][0]) + 1; mn[u][0][1] = min(mn[c1][1][1] + mn[c2][2][1], mn[c1][2][1] + mn[c2][1][1]); mn[u][0][2] = min(mn[c1][1][2] + mn[c2][2][2], mn[c1][2][2] + mn[c2][1][2]); mn[u][1][0] = min(mn[c1][0][0] + mn[c2][2][0], mn[c1][2][0] + mn[c2][0][0]); mn[u][1][1] = min(mn[c1][0][1] + mn[c2][2][1], mn[c1][2][1] + mn[c2][0][1]) + 1; mn[u][1][2] = min(mn[c1][0][2] + mn[c2][2][2], mn[c1][2][2] + mn[c2][0][2]); mn[u][2][0] = min(mn[c1][0][0] + mn[c2][1][0], mn[c1][1][0] + mn[c2][0][0]); mn[u][2][1] = min(mn[c1][0][1] + mn[c2][1][1], mn[c1][1][1] + mn[c2][0][1]); mn[u][2][2] = min(mn[c1][0][2] + mn[c2][1][2], mn[c1][1][2] + mn[c2][0][2]) + 1; } else if(c1) { //有一个儿子 dfs(c1); mx[u][0][0] = max(mx[c1][1][0], mx[c1][2][0]) + 1; mx[u][0][1] = max(mx[c1][1][1], mx[c1][2][1]); mx[u][0][2] = max(mx[c1][1][2], mx[c1][2][2]); mx[u][1][0] = max(mx[c1][0][0], mx[c1][2][0]); mx[u][1][1] = max(mx[c1][0][1], mx[c1][2][1]) + 1; mx[u][1][2] = max(mx[c1][0][2], mx[c1][2][2]); mx[u][2][0] = max(mx[c1][0][0], mx[c1][1][0]); mx[u][2][1] = max(mx[c1][0][1], mx[c1][1][1]); mx[u][2][2] = max(mx[c1][0][2], mx[c1][1][2]) + 1; mn[u][0][0] = min(mn[c1][1][0], mn[c1][2][0]) + 1; mn[u][0][1] = min(mn[c1][1][1], mn[c1][2][1]); mn[u][0][2] = min(mn[c1][1][2], mn[c1][2][2]); mn[u][1][0] = min(mn[c1][0][0], mn[c1][2][0]); mn[u][1][1] = min(mn[c1][0][1], mn[c1][2][1]) + 1; mn[u][1][2] = min(mn[c1][0][2], mn[c1][2][2]); mn[u][2][0] = min(mn[c1][0][0], mn[c1][1][0]); mn[u][2][1] = min(mn[c1][0][1], mn[c1][1][1]); mn[u][2][2] = min(mn[c1][0][2], mn[c1][1][2]) + 1; } else { //没有儿子 mx[u][0][0] = 1; mx[u][0][1] = 0; mx[u][0][2] = 0; mx[u][1][0] = 0; mx[u][1][1] = 1; mx[u][1][2] = 0; mx[u][2][0] = 0; mx[u][2][1] = 0; mx[u][2][2] = 1; mn[u][0][0] = 1; mn[u][0][1] = 0; mn[u][0][2] = 0; mn[u][1][0] = 0; mn[u][1][1] = 1; mn[u][1][2] = 0; mn[u][2][0] = 0; mn[u][2][1] = 0; mn[u][2][2] = 1; } } int main() { scanf("%s", str); build(); dfs(1); printf("%d %d\n", max(mx[1][0][0], max(mx[1][1][0], mx[1][2][0])), min(mn[1][0][0], min(mn[1][1][0], mn[1][2][0]))); }