Color a Tree HDU - 6241

/*
十分巧妙的二分
题意选最少的点涂色
使得满足输入信息:
1 x的子树涂色数不少于y 
2 x的子树外面涂色数不少于y 
我们若是把2转化到子树内最多涂色多少
就可以维护这个最小和最大 
如果我们二分出了答案 就可以完成转化
转化后也恰好可以判断二分是否合法 
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 100010
using namespace std;
int T,n,m,num,ans,head[maxn],L[maxn],R[maxn],a[maxn],b[maxn],s[maxn];
struct node{
    int v,pre;
}e[maxn*2];
void Add(int from,int to){
    num++;e[num].v=to;
    e[num].pre=head[from];
    head[from]=num;
}
bool Dfs(int now,int from){
    int l=0,r=1;
    for(int i=head[now];i;i=e[i].pre){
        int v=e[i].v;
        if(v==from)continue;
        if(Dfs(v,now)==0)return 0;
        l+=L[v];r+=R[v];
    }
    L[now]=max(L[now],l);
    R[now]=min(R[now],r);
    return L[now]<=R[now];
}
bool Judge(int C){
    for(int i=1;i<=n;i++){
        L[i]=0;R[i]=n;
    }
    for(int i=1;i<=n;i++){
        L[i]=a[i];R[i]=min(C-b[i],s[i]);
        if(L[i]>s[i])return 0;
        if(b[i]>n-s[i])return 0;
    }
    return Dfs(1,0)&&L[1]<=C&&R[1]>=C;
}
void dfs(int now,int from){
    s[now]=1;
    for(int i=head[now];i;i=e[i].pre){
        int v=e[i].v;
        if(v==from)continue;
        dfs(v,now);s[now]+=s[v];
    }
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);int u,v;
        num=0;ans=-1;
        memset(head,0,sizeof(head));
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            Add(u,v);Add(v,u);
        }
        dfs(1,0);
        scanf("%d",&m);
        while(m--){
            scanf("%d%d",&u,&v);a[u]=max(a[u],v);
        }
        scanf("%d",&m);
        while(m--){
            scanf("%d%d",&u,&v);b[u]=max(b[u],v);
        }
        int l=0,r=n;
        while(l<=r){
            int mid=(l+r)/2;
            if(Judge(mid)){
                ans=mid;r=mid-1;
            }
            else l=mid+1; 
        }
        printf("%d\n",ans);
    }
    return 0;
}

Color a Tree

 HDU - 6241 

猜你喜欢

转载自www.cnblogs.com/yanlifneg/p/9432177.html