欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

bzoj1864: [Zjoi2006]三色二叉树(树形DP)

程序员文章站 2022-06-24 12:43:17
题目: "1864: [Zjoi2006]三色二叉树" 解析: 用$f[u][0/1/2]$表示以$u$为根,颜色为绿/红/蓝时最多的数量 转移没啥好说的 $f[u][0] = max(f[l][1] + f[r][2], f[l][2] + f[r][1]) + 1$ $f[u][1/2] = m ......

题目:

1864: [zjoi2006]三色二叉树

解析:

\(f[u][0/1/2]\)表示以\(u\)为根,颜色为绿/红/蓝时最多的数量
转移没啥好说的
\(f[u][0] = max(f[l][1] + f[r][2], f[l][2] + f[r][1]) + 1\)
\(f[u][1/2] = max(f[l][0] + f[r][2/1], f[l][2/1] + f[r][0])\)
最小值同理
建树的话递归建树就可以了

代码:

#include <bits/stdc++.h>
using namespace std;

const int n = 5e5  +10;

int n, m, num, rt;
int t[n][2], f[n][3];

char s[n];

inline void build(int &x) {
    x = ++num;
    if (s[x] == '0') return;
    if (s[x] == '1') build(t[x][0]);
    if (s[x] == '2') build(t[x][0]), build(t[x][1]);
}

void max(int u) {
    if (!u) return;
    int l = t[u][0], r = t[u][1];
    max(l), max(r);
    f[u][0] = max(f[l][1] + f[r][2], f[l][2] + f[r][1]) + 1;
    f[u][1] = max(f[l][0] + f[r][2], f[l][2] + f[r][0]);
    f[u][2] = max(f[l][0] + f[r][1], f[l][1] + f[r][0]);
}

void min(int u) {
    if (!u) return;
    int l = t[u][0], r = t[u][1];
    min(l), min(r);
    f[u][0] = min(f[l][1] + f[r][2], f[l][2] + f[r][1]) + 1;
    f[u][1] = min(f[l][0] + f[r][2], f[l][2] + f[r][0]);
    f[u][2] = min(f[l][0] + f[r][1], f[l][1] + f[r][0]);
}

int main() {
    cin >> (s + 1);
    build(rt);
    max(rt);
    cout << max(f[rt][0], max(f[rt][1], f[rt][2])) << " ";
    memset(f, 0, sizeof f);
    min(rt);
    cout << min(f[rt][0], min(f[rt][1], f[rt][2]));
    return 0;
}