[cf] 746 div2 C. Bakry and Partitioning

前言

T a g : Tag: Tag:异或 dfs *1700
传送门 :

题意 :
给定一棵树,你可以删除最少 1 1 1,对多 k − 1 k-1 k1 条边,询问是否可以使得删除边之后,每个连通分量中的异或和相等

思路 :

考虑删除一条边( k = 2 k=2 k=2)的情况

a x ⊕ ( a 1 ⊕ a 2 . . . . a n ) = 0 a_x \oplus(a_1\oplus a_2....a_n)=0 ax(a1a2....an)=0

也就是 a 1 ⊕ a 2 ⊕ a 3 . . . . . a n = s u m = 0 a_1\oplus a_2\oplus a_3.....a_n = sum= 0 a1a2a3.....an=sum=0

如果 s u m ! = 0 sum!=0 sum!=0,那么因为两个连通块需要异或和相同 b ⊕ b = s u m = 0 b\oplus b=sum=0 bb=sum=0,但是 s u m ! = 0 sum!=0 sum!=0

因此 k = 2 k=2 k=2的时候,只有 s u m = 0 sum=0 sum=0是合法的

然后我们考虑删除多条边的情况 k > = 3 k>=3 k>=3


首先这里抛出一个贪心的思路 :
在异或考虑最优的情况下 :
如果选择 三个商品异或相同 并且 五个商品异或也相同,那么我们考虑选择三个商品的最优
up:电音不抖腿


因此我们可以 d f s dfs dfs每一个子树,然后计算其异或和,当且仅当第一次 t o t a l = = s u m total==sum total==sum的时候,我们就进行一次分割

同时又因为 a ⊕ a ⊕ a = a a\oplus a \oplus a =a aaa=a因此最少都需要两个割点,所以最后判断分割的点是否是两个以上即可

code :

vector<int> g[N];
int n,k;
int w[N];
int cnt;

int total;

int dfs(int u,int fa){
	int val =  w[u];
	
	for(auto x :  g[u]){
		if(x == fa)continue;
		
		int tmp = dfs(x,u);
		if(tmp == total) cnt ++;
		else val^=tmp;
		
	}
	return val;
	
}
void solve(){
	cin>>n>>k;
	total = 0 ;
	cnt = 0;
	
	
	for(int i = 1;i<=n; i++ )g[i].clear();
	for(int i = 1;i<=n; i++ ){
		cin>>w[i];
		total^=w[i];
	}
	
	for(int i=1;i<n; i++){
		int u,v;cin>>u>>v;
		g[u].pb(v);
		g[v].pb(u);
	}
	
	if(total == 0){
		cout<<"YES"<<endl;
		return;
	}
	
	if(k<=2){
		cout<<"NO"<<endl;
		return;
	}
	
	
	dfs(1,-1);
	if(cnt > 1){
		cout<<"YES"<<endl;
		return;
	}
	
	cout<<"NO"<<endl;
	
}

int main(){
    int t;cin>>t;while(t--)
    solve();
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值