题解: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";
    }
}
posted @ 2026-08-18 23:06  Monotonic_Deque  阅读(8)  评论(0)    收藏  举报