Bakry and Partitioning—CF1592C
这个题不好写,即使看提交也要看好长时间(可能是因为我菜)。
思路
本来写了很长,但后来发现那个方法不太好理解,就改了一部分。
关键地方我写了注释。
C o d e Code Code
#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int n, k;
int a[N];
int ed[2 * N], ne[2 * N], he[N], idx;
int xor_all; // n点的异或和
int num; // 树中异或和等于xor_all的块数
void add(int u, int v) {
ed[idx] = v, ne[idx] = he[u], he[u] = idx ++;
}
int dfs(int u, int last) {
int xr = a[u];
for (int i = he[u]; i != -1; i = ne[i]) {
int j = ed[i];
if (j != last) {
xr ^= dfs(j, u);
}
}
if (xr == xor_all) {
num ++;
xr = 0;
}
return xr;
}
void solve() {
cin >> n >> k;
for (int i = 1; i <= n; i ++) {
he[i] = -1;
}
xor_all = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
xor_all ^= a[i];
}
for (int i = 1; i <= n - 1; i ++) {
int u, v; cin >> u >> v;
add(u, v);
add(v, u);
}
if (k == 2) {
/*
只能把树分成两个异或和相等的块,
设这两块的异或和都是a,
所以xor_all = a ^ a = 0
*/
if (xor_all == 0) {
cout << "YES\n";
} else {
cout << "NO\n";
}
} else { // k >= 3
num = 0;
dfs(1, 0);
/*
因为这颗树所能分成的异或和相等的块数
的奇偶性不变(因为可以把任意相邻的3块合并
为1块),
所以能分成奇数块、偶数块异或和相等的树
分别能分成3块、2块异或和相等的块。
如果是偶数块(能分成2块),易知xor_all == 0;
如果是奇数块(能分成3块),我们只需要判断
块数是否 > 1即可(当然xor_all时也可以)。
*/
if (num % 2 == 0 && xor_all == 0 ||
num % 2 != 0 && (num > 1 || xor_all == 0)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T; cin.get();
while (T --) solve();
return 0;
}