Bakry and Partitioning(树、xor理解、dfs、思维)

传送门
题目:
在这里插入图片描述
Example
input
5
2 2
1 3
1 2
5 5
3 3 3 3 3
1 2
2 3
1 4
4 5
5 2
1 7 2 3 5
1 2
2 3
1 4
4 5
5 3
1 6 4 1 2
1 2
2 3
1 4
4 5
3 3
1 7 4
1 2
2 3
output
NO
YES
NO
YES
NO
在这里插入图片描述
大致题意:
给出包含 n n n个节点 n − 1 n-1 n1条边的一棵树,每个节点有对应的点权,
给出 k k k,要求删除至少一条边,至多 k − 1 k-1 k1条边,
若存在某种方案,使删边后的森林中,每棵树的所有节点总异或值都相等,输出 y e s yes yes,反之 n o no no

思路:
由已知得到异或和的规律为:
x ⨁ x = 0 x \bigoplus x = 0 xx=0
x ⨁ x ⨁ x = x x \bigoplus x\bigoplus x = x xxx=x
所以:

假设原树的总异或和为 x x x,分析 k k k可知,最终方案有两种可能:删一条边(拆为偶数个)或删两条边(拆为奇数个):
1、若 x = 0 x=0 x=0,随意断开一条边即可。(此时一定是异或和相等的两棵树) x ⨁ x = 0 x \bigoplus x = 0 xx=0

2、若 x ! = 0 x!=0 x!=0,若能成立则存在断开后一定为每棵树异或和均等于原树的总异或和 x x x,且需要找到至少两个。
s o so so:若我们能找到到两块不相交的异或和为原树总异或和 x x x的连通块,且 k − 1 k-1 k1的值需要大于或等于 2 2 2(断开两条边,形成三棵树) x ⨁ x ⨁ x = x x \bigoplus x\bigoplus x = x xxx=x

(我们可以通过找到根为v的树异或和等于原树的总异或和x后将此位置的值标记为0,即可避免连通块出现相交的情况)
通过dfs将以每个节点为根的子树都找一遍
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],b[N],num,sum;
vector<int>g[N];
void dfs(int u,int fa){
	b[u]=a[u];
	for(auto v:g[u]){
		if(v^fa){//不包括fa,遍历此时根u的子树所有点 
			dfs(v,u);
			b[u]^=b[v];
		}
	}
	if(b[u]==sum){
		num++;//计数成功的个数 
		b[u]=0;//将确定可以成功的子树删去 
	}
}
int main(){
	int t,n,k;cin>>t;
	while(t--){
		sum=0,num=0;
		cin>>n>>k;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			sum^=a[i];
			g[i].clear();
		}
		for(int i=0;i<n-1;i++){
			int u,v;
			cin>>u>>v;
			g[u].push_back(v);
			g[v].push_back(u);
		} 
		
		if(sum==0)cout<<"YES"<<endl;
		else{
			dfs(1,0);
			if(k-1>=2&&num>=2)cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值