题意:给定一棵树,每个节点有权值。将这棵树分为若干个块,使得每个块的异或和都相等,且块的个数不能多于 k 。问是否可行。
分析:
- 求出整棵树的异或和,设为 sum 。
- 如果 sum 为零,显然可行。
- 如果 sum 不为零,且 k < 3 ,不可行。
- 如果 sum 不为零,且 k ≥ 3 。那么最后分得的块的异或和必须为 sum ,且块的个数为奇数个。我们只需要 dfs 一遍,每当找到一颗子树异或和为 sum ,便将它分成一个块,并从原本的树中删除,最后分成的块的数量 ≥ 3 便是可行的。

#include<bits/stdc++.h> #define ll long long #define ls u<<1 #define rs u<<1|1 #define mm(x) memset(x,0,sizeof(x)) #define debug(x) cout << #x << ":" << x << ' ' using namespace std; int read() { int a=0;int f=0;char p=getchar(); while(!isdigit(p)){f|=p=='-';p=getchar();} while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();} return f?-a:a; } const int INF=998244353; int T; int n,m; int val[200050]; int sum; int head[200050]; int nex[400050]; int ver[400050]; int tot,cnt; void add(int x,int y) { ++tot; nex[tot]=head[x]; head[x]=tot; ver[tot]=y; } void dfs(int u,int fa) { for(int i=head[u];i;i=nex[i]) { int v=ver[i]; if(v==fa) continue; dfs(v,u); val[u]^=val[v]; } if(val[u]==sum) ++cnt,val[u]=0; } int main() { T=read(); while(T--) { n=read(); m=read()-1; sum=0; tot=0; for(int i=1;i<=n;++i) head[i]=0; for(int i=1;i<=n;++i) val[i]=read(); for(int i=1;i<=n;++i) sum^=val[i]; for(int i=1;i<n;++i) { int x=read(); int y=read(); add(x,y); add(y,x); } if(sum==0) puts("YES"); else if(m<2) puts("NO"); else { cnt=0; dfs(1,0); if(cnt>=2) puts("YES"); else puts("NO"); } } return 0; }