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

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

沒有 cpc ant tar tin 傳送門 表示 每天 blank

傳送門
題意:給定一棵帶權樹的形態, 但是並不知道每天條邊的具體權重.

然後給m個信息, 信息格式為u v val, 表示在樹上u 到 v 的路徑上經過的邊的權重的異或和為val, 問前面最多有多少個信息是不沖突的.

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

去年比賽的時候還不會帶權並查集(逃

註:註意bool型函數沒有返回值會默認返回為false.

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
int n, m , fa[N], V[N];
void init() {
    for(int i=0;i<=n;i++) {
        fa[i] = i;
        V[i] = 0;
    }
}

int Find(int x) {
    if(fa[x] == x) return x;
    
int tmp = fa[x]; fa[x] = Find(fa[x]); V[x] ^= V[tmp]; return fa[x]; } bool join(int u,int v,int k) { int fu = Find(u); int fv = Find(v); if(fu != fv) { fa[fu] = fa[fv]; V[fu] = V[u]^V[v]^k; return true; } if((V[u]^V[v])!=k) return
false; return true; } int main () { int T,cas; scanf("%d",&T); while (T--) { scanf("%d %d", &n, &m); init(); for(int i=1; i<n; i++) { int u,v; scanf("%d %d",&u,&v); } int t = m+1; for(int i=1;i<=m;i++) { int u,v,val; scanf("%d %d %d",&u, &v, &val); if(t != m+1) continue; if(!join(u,v,val)) t = i; } printf("%d\n",t-1); } return 0; }

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