BZOJ 1864: [Zjoi2006]三色二叉树

一眼切题的感觉太爽了= =

f [ i ] [ 0 ] 表示节点 i 不是绿色时子树 i 最多有多少绿色节点, f [ i ] [ 1 ] 表示节点 i 是绿色时子树 i 最多有多少绿色节点。

因为合并状态的时候与当前节点是否为绿色有关,所以要讨论节点是否为绿色。

还是感觉敲码的时间有点长……

#include <cstdio>
#include <cstring>
#include <vector>

const int N = 500005;

char s[N];
int n, f[N][2], g[N][2], ch[N][2];

int max(int x, int y) {
    if (x >= y) return x; return y;
}
int min(int x, int y) {
    if (x <= y) return x; return y;
}
void build(int cur, int fa) {
    if (ch[fa][0]) ch[fa][1] = cur;
    else ch[fa][0] = cur;
    if (s[cur-1] == '0') return;
    build(++n, cur);
    if (s[cur-1] == '2') build(++n, cur);
}
void dp(int u) {
    if (ch[u][0]) dp(ch[u][0]);
    if (ch[u][1]) dp(ch[u][1]);
    f[u][1] = f[ch[u][0]][0] + f[ch[u][1]][0] + 1;
    f[u][0] = max(f[ch[u][0]][0] + f[ch[u][1]][1], f[ch[u][0]][1] + f[ch[u][1]][0]);
    g[u][1] = g[ch[u][0]][0] + g[ch[u][1]][0] + 1;
    g[u][0] = min(g[ch[u][0]][0] + g[ch[u][1]][1], g[ch[u][0]][1] + g[ch[u][1]][0]);
}

int main() {
    scanf("%s", s);
    build(++n, 0);
    dp(1);
    printf("%d %d\n", max(f[1][0], f[1][1]), min(g[1][0], g[1][1]));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/milkyyyyy/article/details/81148830