BZOJ -1864: [Zjoi2006]三色二叉树

1864: [Zjoi2006]三色二叉树

Time Limit: 1 Sec Memory Limit: 64 MB Submit: 662 Solved: 472
[Submit][Status][Discuss] Description
这里写图片描述 Input

仅有一行,不超过500000个字符,表示一个二叉树序列。

Output

输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

Sample Input

1122002010

Sample Output

5 2

HINT

Source

Day1

树形DP,不难

f[i][j]表示i节点颜色为j的最小花费。   2为绿色。
一个孩子时:f[i][0]=max(f[son[i]][1],f[son[i]][2]);
               f[i][1]=max(f[son[i]][0],f[son[i]][2]);
               f[i][2]=max(f[son[i]][1],f[son[i]][0])+1;
两个时:   f[i][0]=max(f[ls[i]][1]+f[rs[i]][2],f[ls[i]][2]+f[rs[i]][1]);
          f[i][1]=max(f[ls[i]][0]+f[rs[i]][2],f[ls[i]][2]+f[rs[i]][0]);
          f[i][2]=max(f[ls[i]][1]+f[rs[i]][0],f[ls[i]][0]+f[rs[i]][1])+1;

输入不好处理呦,我用的递归?!
代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
const int maxn = 500010;
using namespace std;
struct tree
{
    int sum;
    int son[3];
}node[maxn];
int tot;
int f[maxn][3];
int g[maxn][3];
int my_min(int x,int y,int z)
{
    return min(min(x,y),z);
}
int my_max(int x,int y,int z)
{
    return max(max(x,y),z);
}
int read()
{
    tot++;
    int id=tot;
    char c=getchar();
    c=c-'0';
    for(int i=1;i<=c;i++)
    {
        node[id].sum++;
        node[id].son[i]=read();
    }
    return id;
}
void dp(int x)
{
    int s=node[x].sum;
    int u=node[x].son[1];
    int v=node[x].son[2];
    if(u) dp(u);
    if(v) dp(v);
    if(s==1)
    {
        f[x][0]=min(f[u][1],f[u][2]);
        f[x][1]=min(f[u][0],f[u][2]);
        f[x][2]=min(f[u][1],f[u][0]);
        g[x][0]=max(g[u][1],g[u][2]);
        g[x][1]=max(g[u][0],g[u][2]);
        g[x][2]=max(g[u][1],g[u][0]);
    }
    if(s==2)
    {
        f[x][0]=min(f[u][1]+f[v][2],f[u][2]+f[v][1]);
        f[x][1]=min(f[u][0]+f[v][2],f[u][2]+f[v][0]);
        f[x][2]=min(f[u][1]+f[v][0],f[u][0]+f[v][1]);
        g[x][0]=max(g[u][1]+g[v][2],g[u][2]+g[v][1]);
        g[x][1]=max(g[u][0]+g[v][2],g[u][2]+g[v][0]);
        g[x][2]=max(g[u][1]+g[v][0],g[u][0]+g[v][1]);
    }
    f[x][2]++;
    g[x][2]++;
}
int main()
{
    read();
    dp(1);
    printf("%d %d",my_max(g[1][0],g[1][1],g[1][2]),my_min(f[1][0],f[1][1],f[1][2]));
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值