题目链接
题意:
有一个\(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;
}