1. 程式人生 > >2017 ACM/ICPC 新疆賽區 I 題 A Possible Tree 【帶權並查集】

2017 ACM/ICPC 新疆賽區 I 題 A Possible Tree 【帶權並查集】

傳送門
題意:給定一棵帶權樹的形態, 但是並不知道每天條邊的具體權重. 然後給m個資訊, 資訊格式為u v val, 表示在樹上u 到 v 的路徑上經過的邊的權重的異或和為val, 問前面最多有多少個資訊是不衝突的.

思路:首先很明顯的我們要維護一系列不知道的資訊, 看衝不衝突的那就是帶權並查集沒跑了, 此時r[v] 表示v到這棵樹的根節點(雖然題目沒給, 但是我們可以假設一個)的路徑異或和, 那麼此時的每條資訊相當於是告訴你r[u] ^ r[v]的值, 注意異或的特性. 所以對於每條資訊維護好當前的集合的資訊, 如果遇到某次的連個點已經在一個集合中時, 那麼他們之間的異或值也應該被確定了, 如果不等於題目的值那就是衝突的了… 壓縮路徑時根據r代表的意義, 所以就是r[v] ^= r[fav]; 這道題還是算帶權並查集中較簡單的那種…. 還是挺好的題目.
去年比賽的時候還不會帶權並查集(逃

注:注意bool型函式沒有返回值會預設返回為false.
AC Code

const int maxn = 1e5+5;
int fa[maxn], r[maxn];
int n;
void init() {
    for (int i = 0 ; i <= n ; i ++) {
        fa[i] = i;
        r[i] = 0;
    }
}
int Find(int x) {
    if (fa[x] == x) return x;
    else {
        int tmp = fa[x];
        fa[x] = Find(fa[x]);
        r[x] ^= r[tmp];
        return
fa[x]; } } bool Un(int u, int v, int s) { int fu = Find(u); int fv = Find(v); if (fu != fv) { fa[fu] = fv; r[fu] = r[u] ^ r[v] ^ s; return true; } if ((r[u] ^ r[v]) != s) return false; else return true; } void solve() { int m; scanf("%d%d"
, &n, &m); init(); for (int i = 1 ; i < n ; i ++) { int u, v; scanf("%d%d", &u, &v); } int flag = 0; for (int i = 1 ; i <= m ; i ++) { int u, v, s; scanf("%d%d%d", &u, &v, &s); if (!Un(u, v, s) && !flag) { flag = i; } } printf("%d\n", flag - 1); }