UVa 12232 Exclusive-OR (帶權並查集)
阿新 • • 發佈:2021-09-04
題目連結:https://www.luogu.com.cn/problem/UVA12232
對於條件 \(p \oplus q = v\),將 \(p\) 所在並查集和 \(q\) 所在並查集合並,權值為 \(d[p] \oplus d[q]\oplus v\) 即可
對於條件 \(p = v\),建立一棵虛擬節點,值為 \(0\),按上面合併即可,注意要以虛擬節點為根
查詢需要保證每個並查集中需要查詢的值有偶數個(虛擬節點所在並查集除外,因為虛擬節點值已知),否則不知道值是多少
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 40010; int n, Q; int fa[maxn], d[maxn]; int nod[maxn], cnt[maxn]; char s[100]; int find(int x){ if(fa[x] != x) { int rt = find(fa[x]); d[x] ^= d[fa[x]]; return fa[x] = rt; } else return x; } ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; } int main(){ int kase = 0; while(scanf("%d%d", &n, &Q) && n){ printf("Case %d:\n", ++kase); int tot = 0; for(int i = 0 ; i <= n ; ++i) fa[i] = i, d[i] = 0, cnt[i] = 0; int p, q, val, k; int omit = 0; for(int i = 1 ; i <= Q ; ++i){ scanf("%s", s); if(s[0] == 'I'){ ++tot; gets(s); if(sscanf(s, "%d%d%d", &p, &q, &val) == 2){ val = q; q = n; } if(omit) continue; int u = find(p), v = find(q); if(u == v){ if((d[p] ^ d[q]) != val){ printf("The first %d facts are conflicting.\n", tot); omit = 1; } } else{ if(u == n) swap(u, v); // 以虛擬節點作為根,方便後續查詢 fa[u] = v; d[u] = (d[p] ^ d[q] ^ val); } } else{ scanf("%d", &k); vector<int> rt; rt = vector<int>(); int ans = 0; for(int j = 1 ; j <= k ; ++j) { scanf("%d", &nod[i]); int u = find(nod[i]); rt.push_back(u); cnt[u] ^= 1; ans ^= d[nod[i]]; } if(omit) continue; int flag = 0; for(auto u : rt) { if((cnt[u] & 1) && (u != n)) { flag = 1; printf("I don't know.\n"); break; } } if(!flag) { printf("%d\n", ans); } for(auto u : rt) cnt[u] = 0; } } printf("\n"); } return 0; }