Treelabeling-(思维)

72 篇文章 1 订阅

DIV2-D

题意:
给出n个点的树,每个点可以有一个权值,然后a和b互通的条件是a^b<=min(a,b),然后两个人一人操作一次,如何构造使得后手胜利的次数多。输就是到我了但是没法走了。

思考:
就是如何狗仔,是的数上面任意两点是不互通的,可以对整个树进行二分图染色,然后对两个点集分配权值,想要两点不通,那么a^b>min(a,b)意思就是,a和b的最高位不同,所以先把每个数的最高位0和1进行分类,然后再去赋值。

代码:

int T,n,m;
int va[N];
int cnt0,cnt1;
int col[N],num[N],anw[N];

vector<int > e[N];

void dfs(int now,int p,int c)
{
	col[now] = c;
	if(c) cnt1++;
	else cnt0++;
	for(auto spot:e[now])
	{
		if(spot==p) continue;
		dfs(spot,now,c^1);
	}
}

signed main()
{
	IOS;
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			e[i].clear();
			col[i] = num[i] = anw[i] = 0;
		}
		for(int i=1;i<n;i++)
		{
			int a,b;
			cin>>a>>b;
			e[a].pb(b);
			e[b].pb(a);
		}
		cnt0 = cnt1 = 0;
		dfs(1,0,0);
		if(cnt0>cnt1) //这里让0颜色成为少数是因为,数最高位为0的还是多的,为1的少,因为0颜色需要1的权值,所以尽量让0颜色少
		{
			swap(cnt0,cnt1);
			for(int i=1;i<=n;i++) col[i] ^= 1;
		}
		for(int i=1;i<=n;i++)
		{
			int now = 30;
			while(now--)
			{
				if(i&(1<<now))
				break;
			}
			if(cnt0&(1<<now)) num[i] = 0;
			else num[i] = 1;
		}
		int sum0 = 1,sum1 = 1;
		for(int i=1;i<=n;i++)
		{
			if(col[i]==0)
			{
				while(num[sum0]==1) sum0++;
				anw[i] = sum0++;
			}
			else
			{
				while(num[sum1]==0) sum1++;
				anw[i] = sum1++;
			}
		}
		for(int i=1;i<=n;i++) cout<<anw[i]<<" ";
		cout<<"\n";
	}
}

总结:
对于这种思考要想想如何去操作,想到分为两个点集然后去染色和赋值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值