用途
要素がどの集合に属しているかを判定し,部分集合の濃度や部分集合の集合を得る.
計算量
$ O(\alpha(n)) $, $\alpha$はAckermann関数の逆関数
使い方
宣言
クエリ
マージ
aが属する集合と,bが属する集合をマージする
同一の集合か判定
a,bが同一の集合に属しているか判定する
集合サイズ
aが属する集合の濃度を返す
部分集合の集合
でvector{部分集合0, 部分集合1, …}を得る.
実装
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
| class UnionFind {
public:
int n;
vector<int> p;
UnionFind(int _n) : n(_n), p(_n, -1) {}
bool merge(int a, int b) {
int x = root(a), y = root(b);
if (x == y)
return false;
if (-p[x] < -p[y])
swap(x, y);
p[x] += p[y], p[y] = x;
return true;
}
bool isSame(int a, int b) {
return root(a) == root(b);
}
int root(int a) {
if (p[a] < 0)
return a;
return p[a] = root(p[a]);
}
int size(int a) {
return -p[root(a)];
}
vector<vector<int>> groups() {
vector<int> buf(n), size(n);
for (int i = 0; i < n; i++) {
buf[i] = root(i);
size[buf[i]]++;
}
vector<vector<int>> res(n);
for (int i = 0; i < n; i++)
res[i].reserve(size[i]);
for (int i = 0; i < n; i++)
res[buf[i]].push_back(i);
res.erase(remove_if(res.begin(), res.end(), [&](const vector<int> &v) { return v.empty(); }), res.end());
return res;
}
};
|
Verify
//TODO