CF1592C. Bakry and Partitioning
阿新 • • 發佈:2021-10-04
原題連結:CF1592C. Bakry and Partitioning
題意:
給定一個\(n\)個點,\(n - 1\)條邊的樹,並且每個點都有權值\(w_i\),讓你最少割掉一條邊最多割掉\(k - 1\)條邊使得劃分後的子樹異或和相等。
思路:
-
首先根據異或的交換律結合律得知:如果所有點的權值\(\sum\nolimits_{i = 1}^n w_i = 0\),那麼我們隨意切一刀就行,所以這種情況下必然滿足題意。
-
再根據異或的一個性質應用,\(x \,\, \oplus \,\, x \,\, \oplus \,\, x \,\, \oplus \,\, = x\),考慮到,設\(\sum\nolimits_{i = 1}^n w_i = x\)
令\(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; }