• hdu 6241 Color a Tree 2017 CCPC 哈理工站 L


    Bob intends to color the nodes of a tree with a pen. The tree consists of NN nodes. These nodes are numbered 1,2,...,N1,2,...,N. The root of the tree is node 11. 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+BA+B rules. Each rule is represent by two numbers xixi and yiyi. 
    For the first AA rules, it means that there should be no less than yiyi nodes painted black for the subtree of node xixi. 
    For the other BB rules, it means that there should be no less than yiyi nodes painted black for all nodes except the subtree of node xixi. 
    You need to help Bob to calculate the minimum energy he needs for the painting with all rules proposed by Alice satisfied. 

    InputThe first line is the number of test cases. For each test case, the first line contains one positive number N(1N100000)N(1≤N≤100000), indicating the number of trees nodes. 

    The following N1N−1 lines describe the edges. Each line contains two integers u,vu,v(1u,vN1≤u,v≤N), denoting there is a edge between node uu and node vv. 

    The following one line contains one number AA(A100000A≤100000), indicating the first AArules. 

    The following AA lines describe the first AA rules. Each line contains two numbers xixiand yiyi as described above. 

    The following one line contains one number BB(B100000B≤100000), indicating the other BBrules. 

    The following BB lines describe the other BB rules. Each line contains two numbers xixiand yiyi as described above. 
    OutputFor 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−1instead. 
    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

    题意抽象:

      给定一棵节点数为N的树,现要给节点染色,要求满足A+B条规则:

      前A条规则的输入约定为一组x,y,表示编号为x的节点的子树中要有不少于y个点被染色。

      后B条规则的输入也约定为一组x,y,表示编号为x的节点的子树之外要有不少于y个点被染色。

      求满足条件的最少染色数。无答案返回-1.

      约定输入的树的根节点序号为1.

      数据规模:节点数N100000,边数为N-1,A100000,B100000。

      

    模拟赛的时候没想出来。

    关键在于二分答案,把子树外不少于y个节点被染色转化为子树内最多多少个点被染色。

    然后dfs维护节点的子树能染色点数的区间即可,最后判断是否出现冲突以及二分的答案mid在不在根节点的子树能染色点数的区间中即可。

    O(nlogn)

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    using namespace std;
    const int MAXN=100100;
    int pointer[MAXN];
    int n,tot,A,B,now;
    int low[MAXN],high[MAXN];
    int RuleA[MAXN];
    int RuleB[MAXN];
    int cnt=0;
    struct Edge
    {
        int to,next;
        Edge() {}
        Edge(int b,int nxt) {to=b;next=nxt;}
    }edge[2*MAXN];
    void init()
    {
        tot=0;
        memset(pointer,-1,sizeof(pointer));
        memset(RuleA,0,sizeof(RuleA));
        memset(RuleB,0,sizeof(RuleB));
    }
    inline void addedge(int a,int b)
    {
        edge[tot]=Edge(b,pointer[a]);
        pointer[a]=tot++;
        edge[tot]=Edge(a,pointer[b]);
        pointer[b]=tot++;
    }
    void Input()
    {
        scanf("%d",&n);
        int u,v;
        rep(i,1,n-1)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        scanf("%d",&A);
        int x,y;
        rep(i,1,A)
        {
            scanf("%d%d",&x,&y);
            RuleA[x]=max(y,RuleA[x]);
        }
        scanf("%d",&B);
        rep(i,1,B)
        {
            scanf("%d%d",&x,&y);
            RuleB[x]=max(RuleB[x],y);
        }
    }
    void dfs(int u,int pre)
    {
        int lowsum=0,highsum=0;
        low[u]=RuleA[u];
        high[u]=now-RuleB[u];
        for(int j=pointer[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].to;
            if(v==pre) continue;
            dfs(v,u);
            lowsum+=low[v];
            highsum+=high[v];
        }
        low[u]=max(low[u],lowsum);
        high[u]=min(high[u],highsum+1);
    
    }
    bool check(int k)
    {
        now=k;
        dfs(1,1);
        if(RuleB[1]>0) return 0;
        for(int i=1;i<=n;++i)
        {
            if(high[i]<low[i]) return 0;
        }
        if(k<=high[1]&&k>=low[1]) return 1;
        else return 0;
    }
    int main()
    {
       // freopen("in.txt","r",stdin);
        int TT;scanf("%d",&TT);
        rep(t1,1,TT)
        {
            init();
            Input();
            int l=0,r=n;
            while(l<r)
            {
                int mid=(l+r)>>1;
                if(check(mid)) r=mid;
                else l=mid+1;
            }
            if(!check(l)) printf("-1
    ");
            else printf("%d
    ",l);
        }
        return 0;
    }

     

  • 相关阅读:
    DataGridView 控件和 DataGrid 控件之间的区别
    winform 如何创建mdi属性IsMdiContainer=true
    窗体分为左右两部分,要求在左边栏点击按钮时,右边动态加载窗体
    OLEDBConnection 和SQLConnection 有什么区别
    成为一个顶级设计师的八大秘诀
    青春追梦
    四维领导力:明道、取势、优术、树人
    走好青春
    再贺开业
    骑车在暴雨中有感
  • 原文地址:https://www.cnblogs.com/zhixingr/p/8003748.html
Copyright © 2020-2023  润新知