题解:P17267 [ICPC 2017 Urumqi R] A Possible Tree
P17267 A Possible Tree 题解
我们可以发现树上路径异或其实就等于 \(val(u\to root) \operatorname{xor}val(v\to root)\)。
这个也很好解释。因为异或 \(2\) 次就抵消了,所以 \(val(u\to root) \operatorname{xor}val(v\to root)\) 中 \(LCA(u,v)\to root\) 的部分被抵消了,所以就只剩路径部分了。
我们就会发现这就与树的结构没有任何关系了。这样就可以转化成若干个异或等式。考虑使用带权并查集维护。
设 \(d_i\) 是节点 \(i\) 到根的路径异或。路径压缩的时候处理一下就可以了。
然后就可以愉快的写代码了。
十年 OI 一场空,不开 long long 见祖宗
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int f[N], sz[N], d[N];
pair<int, int> find(int x){
if(f[x] == x) return {x, 0};
auto p = find(f[x]);
d[x] ^= p.second;
f[x] = p.first;
return {f[x], d[x]};
}
signed main() {
int T; cin >> T;
while(T--) {
int n, c;
cin >> n >> c;
for(int i = 1; i <= n; i++) f[i] = i, sz[i] = 1, d[i] = 0;
for(int i = 1, u, v; i < n; i++) cin >> u >> v;
int ans = c;
for(int i = 1; i <= c; i++) {
int u, v, val; cin >> u >> v >> val;
if(ans != c) continue;
auto fu = find(u), fv = find(v);
if(fu.first == fv.first) {
if((fu.second ^ fv.second) != val) {
ans = i - 1;
}
} else {
if(sz[fu.first] > sz[fv.first]) swap(fu, fv);
f[fu.first] = fv.first;
d[fu.first] = fu.second ^ fv.second ^ val;
sz[fv.first] += sz[fu.first];
}
}
cout << ans << "\n";
}
}

浙公网安备 33010602011771号