CF1592C. Bakry and Partitioning

原题链接:CF1592C. Bakry and Partitioning

题意:

给定一个n个点,n1条边的树,并且每个点都有权值wi,让你最少割掉一条边最多割掉k1条边使得划分后的子树异或和相等。

思路:

  1. 首先根据异或的交换律结合律得知:如果所有点的权值i=1nwi=0,那么我们随意切一刀就行,所以这种情况下必然满足题意。

  2. 再根据异或的一个性质应用,xxx=x,考虑到,设i=1nwi=x,那么我们只需要判断这个树是否可以分成三份异或和都可以等于0的子树即可,如果可以,那么还有检查k是否大于2

f[u]表示以u为根节点的子树的所有结点的异或和,那么DFS跑树形DP即可。

// Problem: C. Bakry and Partitioning
// Contest: Codeforces - Codeforces Round #746 (Div. 2)
// URL: https://codeforces.com/contest/1592/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

using namespace std;

const int N = 1E5 + 10, M = N * 2;
int h[N], e[M], ne[M], idx;
int w[N], f[N], cnt = 0;
int n, k;
int xorsum = 0;

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int dfs(int u, int fa) {
	f[u] = w[u];
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (j == fa) continue;
		int t = dfs(j, u);
		f[u] ^= t;
	}
	
	if (f[u] == xorsum) cnt++, f[u] = 0;
	
	return f[u];
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		xorsum = 0, memset(h, -1, sizeof h), idx = 0, cnt = 0;

		scanf("%d%d", &n, &k);
		
		for (int i = 1; i <= n; i++) {
			cin >> w[i];
			xorsum ^= w[i];
			f[i] = 0;
		}
		//case 1:如果数组异或和为0,那么随意切一刀
		//case 2:x xor x xor x = x设总和为x,那么分成三份每一部分都是x
		//令f[u]为以u为根的子树的异或和
		
		for (int i = 0; i < n - 1; i++) {
			int u, v; scanf("%d%d", &u, &v);
			add(u, v), add(v, u);
		}
		
		if (xorsum == 0) puts("YES");
		else {
			dfs(1, -1);
			if (cnt >= 3 && k > 2) puts("YES");
			else puts("NO");
		}
	}
    return 0;
}
posted @   Xxaj5  阅读(79)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示