2017 ACM/ICPC 新疆賽區 I 題 A Possible Tree 【帶權並查集】
阿新 • • 發佈:2019-02-16
傳送門
題意:給定一棵帶權樹的形態, 但是並不知道每天條邊的具體權重. 然後給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);
}