HDU 6241 Color a Tree CCPC2017 Harbin(二分答案+上下界判定)

Color a Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 92    Accepted Submission(s): 17

Problem Description

Bob intends to color the nodes of a tree with a pen. The tree consists of N nodes. These nodes are numbered 1,2,...,N . The root of the tree is node 1 . The initial color of each node is white. Bob can use one unit energy to color one node into black. To prevent Bob being lazy with painting, Alice proposed A+B rules. Each rule is represent by two numbers xi and yi .
For the first A rules, it means that there should be no less than yi nodes painted black for the subtree of node xi .
For the other B rules, it means that there should be no less than yi nodes painted black for all nodes except the subtree of node xi .
You need to help Bob to calculate the minimum energy he needs for the painting with all rules proposed by Alice satisfied.

Input

The first line is the number of test cases. For each test case, the first line contains one positive number N(1N100000) , indicating the number of trees nodes.
The following N1 lines describe the edges. Each line contains two integers u,v ( 1u,vN ), denoting there is a edge between node u and node v .
The following one line contains one number A ( A100000 ), indicating the first A rules.
The following A lines describe the first A rules. Each line contains two numbers xi and yi as described above.
The following one line contains one number B ( B100000 ), indicating the other B rules.
The following B lines describe the other B rules. Each line contains two numbers xi and yi as described above.

Output

For each test case, output a integer donating the minimum energy Bob needs to use with all rules propose by Alice satisfied. If there is no solution, output 1 instead.

Sample Input

 
 
2 5 1 2 2 3 3 4 1 5 2 2 1 5 1 1 2 1 5 1 2 2 3 3 4 1 5 3 1 2 2 2 5 1 1 3 5

Sample Output

 
 
2 -1

Source

2017中国大学生程序设计竞赛-哈尔滨站-重现赛(感谢哈理工)



        CCPC哈尔滨,是一个二分答案专场……

        此题二分,B题二分,还有一个分数规划的二分……

        这是一个非常值得借鉴的二分答案的题目。大致题意:给你一棵树,然后让你对树上的节点进行黑白染色。然后染色有一些要求,对于A类要求,要求在x的子树中,至少有y个节点被染成了黑色;对于B类要求,要求在树的所有节点除了x以及其子树节点外,至少有y个节点被染成了黑色。初始状态树是白色的,现在问你,最少给多少个节点染成黑色之后,能够满足所有的A、B类要求。

        其实遇到这种至多至少,然后询问最少的题目,应该就要想到上下界的判断了。这种题目感觉之前见过,但是想不起来了。我们二分最后的染成黑色的节点数目,然后判定这个答案是否可行。我们发现,对于A类要求,相当于直接对节点x设置了一个下界,表示以他为根的子树含有的黑色节点数目的下界。但是对于B类要求似乎不太好处理。这个时候可以利用转化的思想。在非x以及其子树的节点中至少包含y个黑色节点,那么等价于在x以及其子树的节点中至多包含n-y个黑色节点,由此,我们就可以以此为依据确定一个上界。这样子的话,我们通过dfs,累加每一个儿子节点的上下界,再依此不断缩小上下界。判定在过程中是否有出现上下界不合法的情况,以及我们枚举的答案是否包含在根的上下界之中,来确定当前枚举的答案的正确与否。

        具体实现过程中,我们要注意对于同一个点的要求可能会有多个,不能够使其相互覆盖,而是应该保留特定的要求。因为这一点我倒是wa的好多次。具体见代码:

#include<bits/stdc++.h>
#define N 101000

using namespace std;

int n,up[N],dw[N],d[N],u[N],b[N],sz[N];
vector<int> g[N];

void init()
{
    memset(g,0,sizeof(g));
    memset(b,0,sizeof(b));
    memset(dw,0,sizeof(dw));
}

bool dfs(int x,int fa)
{
    int down=0,UP=1;
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (y==fa) continue;
        if (!dfs(y,x)) return 0;
        down+=d[y]; UP+=u[y];					//累加所有儿子的上下界
    }
    d[x]=max(dw[x],down);						//缩小上下界范围
    u[x]=min(up[x],UP);
    return d[x]<=u[x];							//如果矛盾,则当前枚举答案不可行
}

void getsize(int x,int fa)
{
    sz[x]=1;
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (y==fa) continue;
        getsize(y,x); sz[x]+=sz[y];
    }
}

bool check(int x)
{
    for(int i=1;i<=n;i++)
    {
        up[i]=min(x-b[i],sz[i]);
        if (up[i]<0) return 0;
    }
    return dfs(1,0)&&u[1]>=x&&d[1]<=x;					//最后要求枚举的答案,在根的上下界范围之内
}

int main()
{
    int T_T;
    cin>>T_T;
    while(T_T--)
    {
        init();
        scanf("%d\n",&n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        int m,flag=0;
        getsize(1,0);
        scanf("%d",&m);
        while(m--)
        {
            int x,y; scanf("%d%d",&x,&y);
            dw[x]=max(dw[x],y); if (y>sz[x]) flag=1;			//这里注意这个至少的限制不能直接覆盖,而是取最大的
        }
        scanf("%d",&m);
        while(m--)
        {
            int x,y; scanf("%d%d",&x,&y);
            b[x]=max(y,b[x]);							//这里也是同理
            if (y>n-sz[x]) flag=1;
        }
        if (flag){puts("-1");continue;}
        int l=0,r=n,ans=-1,mid;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if (check(mid)) ans=mid,r=mid-1;
                       else l=mid+1;
        }
        printf("%d\n",ans);
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值