拓展并查集的概念 拓展并查集(Union-Find with Extensions)是对标准并查集(Union-Find)的一种扩展,旨在解决更复杂的问题。
拓展域并查集解决了一种多个有相互关系的并查集,放在一起考虑的问题。一般的并查集应用一般就是判断在不在一个集合,拓展域并查集讲的是多个集合,之间有相互关系一般为相互排斥关系,判断是否在一个集合等。
核心思想 为了解决多种关系相互的问题,我们需要更多的空间来维护。
假如我现在有两种关系,友好和敌对,那么我就需要开两倍的空间$p[2 * n]$其中$p[i]$存储的与i是友好关系的,$p[i + n]$ 存储的是与i是敌对关系的。
以此类推:
$p[a]$存储与a同类的
$p[a+1*n]$存储与a发生第一类关系的
$p[a+2*n]$存储与a发生第二类关系的
$p[a+3*n]$存储与a发生第三类关系的
….
通过这些关系之间的联系,可以很方便的求解。
例题 食物链 我们还是通过食物链 这题来看,这道题有三种关系,同类,食物,天敌。 我們分別用$x$代表同类,$x + n$代表食物,$x + n + n $代表天敌。
当我们要判断$x,y$ 是同类这句话是否是假话时,我们要把如果是假话的情况列举出来:
x的食物是y
x的天敌是y 这两种情况就是假话,对应代码即为$same(x + n,y) , same(x + n + n,y)$两种任意一种成立即为假话。 如果是真话的话,就把 这三类都要$merge$一下
merge(x,y),
merge(x + n,y + n),
merge(x + n + n,y + n + n)
因为x和y是同类的话,他们的食物肯定是同类,他们的天敌肯定是同类。
当我们要判断 $x$ 吃 $y$ 也就是说$y$是$x$的食物,$x$是$y$的天敌。 这句话为假时,情况是:
如果这句话是真话,那么我们合并
merge(x + n , y)
merge(x + n + n, y + n)
merge(x , y + n + n)
可以和带权并查集 里面的比较一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <deque> #include <stack> #include <unordered_map> #include <unordered_set> #include <numeric> #include <iomanip> #define _fio \ ios_base::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0); #define pb(e) push_back(e) #define all(x) (x).begin(), (x).end() #define allr(x) (x).rbegin(), (x).rend() #define endl '\n' using namespace std;using i64 = long long ;using PII = pair<int , int >;const int INF = 0x3f3f3f3f ;struct DSU { std::vector<int > p, siz; DSU () {} DSU (int n) { init (n); } void init (int n) { p.resize (n); std::iota (p.begin (), p.end (), 0 ); siz.assign (n, 1 ); } int find (int x) { while (x != p[x]) { x = p[x] = p[p[x]]; } return x; } bool same (int x, int y) { return find (x) == find (y); } bool merge (int x, int y) { int px = find (x); int py = find (y); if (px == py) { return false ; } siz[px] += siz[py]; p[py] = px; return true ; } int size (int x) { return siz[find (x)]; } };int main () { int n, k, res = 0 ; cin >> n >> k; DSU dsu (3 * (n + 1 )) ; for (int i = 0 , d, x, y; i < k; ++i) { cin >> d >> x >> y; if (x > n || y > n) { res++; continue ; } if (d & 1 ) { if (dsu.same (x + n, y) || dsu.same (x + n + n, y)) { res++; } else { dsu.merge (x, y); dsu.merge (x + n, y + n); dsu.merge (x + n + n, y + n + n); } } else { if (dsu.same (x + n + n, y) || dsu.same (x, y)) { res++; } else { dsu.merge (x + n, y); dsu.merge (x + n + n, y + n); dsu.merge (x, y + n + n); } } } cout << res << endl; return 0 ; }
团伙 团伙 ,这个题只有两种关系,注意的就是,朋友的敌人和自己的敌人不一定是朋友。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <deque> #include <stack> #include <unordered_map> #include <unordered_set> #include <numeric> #include <iomanip> #define _fio \ ios_base::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0); #define pb(e) push_back(e) #define all(x) (x).begin(), (x).end() #define allr(x) (x).rbegin(), (x).rend() #define endl '\n' using namespace std;using i64 = long long ;using PII = pair<int , int >;const int INF = 0x3f3f3f3f ;struct DSU { std::vector<int > p, siz; DSU () {} DSU (int n) { init (n); } void init (int n) { p.resize (n); std::iota (p.begin (), p.end (), 0 ); siz.assign (n, 1 ); } int find (int x) { while (x != p[x]) { x = p[x] = p[p[x]]; } return x; } bool same (int x, int y) { return find (x) == find (y); } bool merge (int x, int y) { int px = find (x); int py = find (y); if (px == py) { return false ; } siz[px] += siz[py]; p[py] = px; return true ; } int size (int x) { return siz[find (x)]; } };int main () { int n, m; cin >> n >> m; DSU dsu (2 * (n + 1 )) ; while (m--) { string op; int x, y; cin >> op >> x >> y; if (op == "F" ) { dsu.merge (x, y); } else { dsu.merge (x + n, y); dsu.merge (x, y + n); } } unordered_set<int > st; for (int i=1 ;i<=n;++i) st.insert (dsu.find (i)); cout << st.size () << endl; return 0 ; }