/* 十分巧妙的二分 题意选最少的点涂色 使得满足输入信息: 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
今日推荐
周排行