Color a Tree 转化+二分 HDU6241

Color a Tree
题面: 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.
题意: 给定大小为N的树,限制点都是白色,让你染色,求最小染色数,有A+B个的限制,A限制表示X子树至少有Y个点被染色。B限制表示X子树之外的那些点,至少有Y个点被染色
思路:
优秀题解
很难想到二分答案。根据A条件我们可以得到每个子树至少有x个点染色;二分整颗树染色的结点数,根据B条件,我们可以得到子数最多有(mid-y)个染色点,然后看每个点是否有矛盾,如果有矛盾,或者整棵树不够染色,输出-1。是否二分成立。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
vector<int>G[N];
int minn[N],maxx[N],sz[N];
int q[N],p[N];
int n,A,B;
void get_size(int u,int fa)
{
	sz[u]=1;
	int tmp=0;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa)
			continue;
		get_size(v,u);
		sz[u]+=sz[v];
		tmp+=minn[v];
	}
	minn[u]=max(tmp,minn[u]);
}

bool dfs(int u,int fa)
{
	int tmp=1;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa)
			continue;
		if(!dfs(v,u))
			return false;
		tmp+=maxx[v];
	}
	maxx[u]=min(maxx[u],tmp);
	if(maxx[u]<minn[u])
		return false;
	return true;
}

bool check(int x)
{
	for(int i=1;i<=n;i++)
		maxx[i]=sz[i];
	for(int i=1;i<=B;i++)
		maxx[q[i]]=min(maxx[q[i]],x-p[i]);
	if(dfs(1,0)&&maxx[1]>=x)
		return true;
	return false;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<=n;i++)
			G[i].clear(),minn[i]=0;
		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);
		}
		scanf("%d",&A);
		for(int i=1;i<=A;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			minn[u]=max(minn[u],v);
		}
		get_size(1,0);
		scanf("%d",&B);
		for(int i=1;i<=B;i++)
		{
			scanf("%d%d",&q[i],&p[i]);
		}
		int l=minn[1],r=n,ans=-1;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(check(mid))
				ans=mid,r=mid-1;
			else
				l=mid+1;
		}
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值