CF1592C. Bakry and Partitioning

原题链接:CF1592C. Bakry and Partitioning

题意:

给定一个\(n\)个点,\(n - 1\)条边的树,并且每个点都有权值\(w_i\),让你最少割掉一条边最多割掉\(k - 1\)条边使得划分后的子树异或和相等。

思路:

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

  2. 再根据异或的一个性质应用,\(x \,\, \oplus \,\, x \,\, \oplus \,\, x \,\, \oplus \,\, = x\),考虑到,设\(\sum\nolimits_{i = 1}^n w_i = 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 @ 2021-10-04 19:51  Xxaj5  阅读(76)  评论(0编辑  收藏  举报