题意: 中文题。
思路: 对于每种情况,可以发现当前节点的连接父亲的边权,并不受子树边权的影响。
比如 当前节点 与父节点边 是 1 改成若干次后偶数次变1, 奇数次变0,并不受子树中边的影响
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> vec[N], tree[N], w[N], tw[N];
int f[N], a[N], vis[N];
void build(int k){
for(int i = 0; i < vec[k].size(); i++){
if(!vis[vec[k][i]]){
int v = vec[k][i];
tree[k].push_back(v);
tw[k].push_back(w[k][i]);
vis[v] = 1;
f[v] = k;
}
}
}
void dfs(int k){
if(tree[k].size() == 0) return;
for(int i = 0; i < tree[k].size(); i++){
int v = tree[k][i];
dfs(v);
a[k] ^= tw[k][i];
}
}
int search(int k, int t){
if(k == 1) {
if(t == 0) return a[1];
for(int i = 0; i < tree[t].size(); i++) {
if(tree[k][i] == t) return a[1] ^ a[t] ^ tw[1][i];
}
}
int num = search(f[k], k);
if(t == 0) return num;
for(int i = 0; i < tree[k].size(); i++) {
if(tree[k][i] == t) return num ^ (a[k] ^ a[t]) ^ tw[k][i];
}
}
void update(int k){
a[k] ^= 1;
if(k == 1) return;
update(f[k]);
}
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m;
memset(f, 0, sizeof(f));
memset(vis, 0, sizeof(vis));
memset(a, 0, sizeof(a));
for(int i = 0; i < N; i++) {
vec[i].clear();
tree[i].clear();
w[i].clear();
tw[i].clear();
}
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
vec[x].push_back(y);
vec[y].push_back(x);
w[x].push_back(z);
w[y].push_back(z);
}
for(int i = 1; i <= m; i++){
int op, x, y, z;
scanf("%d", &op);
if(op == 0) {
int ans = 0;
scanf("%d", &x);
for(int i = 0; i < vec[x].size(); i++) ans ^= w[x][i];
puts(ans % 2 ? "Girls win!" : "Boys win!");
}else {
scanf("%d%d%d", &x, &y, &z);
for(int i = 0; i < vec[x].size(); i++) if(vec[x][i] == y) w[x][i] = z;
for(int i = 0; i < vec[y].size(); i++) if(vec[y][i] == x) w[y][i] = z;
}
}
}
return 0;
}