解题思路:由树的归一性和异或的充分性,容易证明在每个点异或和不等于0的情况下,分成的连通块只能是奇数个。由于树的单链性,最终的每个连通块的异或和只能是所有点值的异或和。

考虑到树的性质,再结合异或的性质,发现偶数个连通块都可以化归为同一个连通块,最终可以意识到,在同一棵树上,如果能够分成奇数个连通块,那么最好最简单且正确的转化方式

一定是转化为三个连通块。或许其中的一个连通块可以分成三个值相等的小连通块,这也是可以接受的。我们只需要最终能利用异或的性质把它们分成起码三个。但是由反证法知道,如果一个连通块不能被分为奇数个值正确的小连通块,那么大连通块的值也必然不正确。换句话讲,我们最后需要的只是能凑出所有点异或和的连通块。

而树上的连通块一定可从子树考虑分割,即DFS。

出题思路:这个题的数据不容易做出来。事实上,在绝大部分情况下,输出的都是"NO"。话句话讲,题意本身就完全是人为的特殊情况。


#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=2e5;
struct Edge{
    int u,v,nxt;
}e[MAXN*2];
int head[MAXN],a[MAXN],cnt=0;

void addEdge(int u,int v){
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}

int needSum=0;//需要的^和 
int okCnt=0;//可以分割的子树 
int dfs(int nowX,int fa){
    int tmpSum=a[nowX];
    for(int i=head[nowX];i;i=e[i].nxt){
        int nowV=e[i].v;
        if(nowV!=fa){    
            tmpSum^=dfs(nowV,nowX);
        }
    }
    if(tmpSum==needSum){
        okCnt++;
        return 0;
    }else{
        return tmpSum;
    }
}

void init(){
    cnt=0;
    needSum=0;
    okCnt=0;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        init();
        int n,k;
        scanf("%d%d",&n,&k);
        
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            needSum^=a[i]; 
            head[i]=0;
        }
        
        for(int i=1;i<=n-1;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            addEdge(u,v);
            addEdge(v,u);
        }
        
        if(needSum==0){
            printf("YES\n");
        }else{
            dfs(1,0);
            if(okCnt>=3&&k>=3){
                printf("YES\n");
            }else{
                printf("NO\n");
            }
        }
    }
    return 0;
}