BZOJ - 1864 三色二叉树 (树形dp)

BZOJ - 1864

中文题题意不解释~

还是比较基础的树形dp~

思路: 每个父亲节点还是由子节点推过来的,所以只需要统计子节点的状态就可以了,用dpa[i][j]来表示涂绿,蓝和啥的时候最多有几个节点是绿色的,dpi则是表示最少有几个节点是绿色的。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 50;
const int inf = 0x3f3f3f3f;
char str[maxn];
int numa[maxn];
int a[maxn][2];
int thi = 0;
int dpa[maxn][3],dpi[maxn][3];
void build(int num,int root)
{
    numa[root] = num;
    if(num >= 1)
    {
        ++thi;
        a[root][0] = thi;
        build(str[thi]-'0', thi);
    }
    if(num >= 2)
    {
        ++thi;
        a[root][1] = thi;
        build(str[thi] -'0',thi);
    }
}
void solve(int u)
{
    if(numa[u] == 0)
    {
        dpa[u][0] = 1, dpa[u][1] = 0, dpa[u][2] = 0;
        dpi[u][0] = 1, dpi[u][1] = 0, dpi[u][2] = 0;
        return;
    }
    if(numa[u] == 1)
    {
        int v = a[u][0];
        solve(v);
        dpa[u][0] = max(dpa[v][1], dpa[v][2]) + 1;
        dpa[u][1] = max(dpa[v][0], dpa[v][2]);
        dpa[u][2] = max(dpa[v][1], dpa[v][0]);

        dpi[u][0] = min(dpi[v][1], dpi[v][2]) + 1;
        dpi[u][1] = min(dpi[v][0], dpi[v][2]);
        dpi[u][2] = min(dpi[v][1], dpi[v][0]);
    }
    else if(numa[u] == 2)
    {
        int v1 = a[u][0], v2 = a[u][1];
        solve(v1);  solve(v2);
        dpa[u][0] = max(dpa[v1][1] + dpa[v2][2], dpa[v1][2] + dpa[v2][1]) + 1;
        dpa[u][1] = max(dpa[v1][0] + dpa[v2][2], dpa[v1][2] + dpa[v2][0]);
        dpa[u][2] = max(dpa[v1][1] + dpa[v2][0], dpa[v1][0] + dpa[v2][1]);

        dpi[u][0] = min(dpi[v1][1] + dpi[v2][2], dpi[v1][2] + dpi[v2][1]) + 1;
        dpi[u][1] = min(dpi[v1][0] + dpi[v2][2], dpi[v1][2] + dpi[v2][0]);
        dpi[u][2] = min(dpi[v1][1] + dpi[v2][0], dpi[v1][0] + dpi[v2][1]);
    }
}

int main()
{
    scanf("%s",str);
    memset(a,-1,sizeof(a));
    build(str[0]-'0',0);
    solve(0);
    int maxi = 0, mini = inf;
    for(int i = 0; i < 3;i ++)
    {
        maxi = max(dpa[0][i], maxi);
        mini = min(dpi[0][i], mini);
    }
    printf("%d %d\n",maxi , mini);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值