题目链接
题意:
有一个\(n\)个节点的树,最少分成两个连通分量,最多分成\(k\)个连通分量,能否将树分成若干个连通分量,其权值异或值相同。
思路:
思路大致都想到了,但想复杂了。
若原本树的权值异或和为\(0\),任意切割一条边,都可以为两个异或和相等的连通分量。
若异或和为\(k\)(不为\(0\)),转化为是否能分成奇数个异或和为\(k\)的连通分量。由异或的性质,最终变为是否能分成三个异或和为\(k\)的联通分量。倒着遍历,若一个结点的子树与本身异或和为\(k\),就切割此子树。最终看切割的连通分量的个数是否大于\(3\)。
code:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <deque>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
// #include <unordered_map>
#define fi first
#define se second
#define pb push_back
#define endl "\n"
#define debug(x) cout << #x << ":" << x << endl;
#define bug cout << "********" << endl;
#define all(x) x.begin(), x.end()
#define lowbit(x) x & -x
#define fin(x) freopen(x, "r", stdin)
#define fout(x) freopen(x, "w", stdout)
#define ull unsigned long long
#define ll long long
const double eps = 1e-15;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
using namespace std;
int n, s[maxn], k, ans, xx[maxn];
vector<int> v[maxn];
int tot;
int dfs(int u, int fa){
xx[u] = s[u];
for(int to : v[u]){
if(to == fa)continue;
dfs(to, u);
xx[u] ^= xx[to];
}
if(xx[u] == ans){
tot ++;
xx[u] = 0;
}
return xx[u];
}
void solve(){
scanf("%d%d", &n, &k);
tot = ans = 0;
if(k == 1)return void(puts("NO"));
for(int i = 1; i <= n; i ++)v[i].clear(), xx[i] = 0;
for(int i = 1; i <= n; i ++)scanf("%d", &s[i]), ans ^= s[i];
for(int i = 1, a, b; i < n; i ++){
scanf("%d%d", &a, &b);
v[a].pb(b), v[b].pb(a);
}
if(!ans)return void(puts("YES"));
if(k <= 2)return void(puts("NO"));
dfs(1, 0);
tot ++;
if(tot >= 3)puts("YES");
else puts("NO");
}
int main(){
int t;
scanf("%d", &t);
while(t --)solve();
return 0;
}