Logo
No results found.
UnionFind
Overview

UnionFind

July 29, 2024
1 min read

用途

要素がどの集合に属しているかを判定し,部分集合の濃度や部分集合の集合を得る.

計算量

O(α(n))O(\alpha(n)), α\alphaはAckermann関数の逆関数

使い方

宣言

UnionFind uf(要素数);

クエリ

マージ

uf.merge(a,b);

aが属する集合と,bが属する集合をマージする

同一の集合か判定

uf.isSame(a,b);

a,bが同一の集合に属しているか判定する

集合サイズ

uf.size(a);

aが属する集合の濃度を返す

部分集合の集合

uf.groups();

vector{部分集合0, 部分集合1, ...}を得る.

実装

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

Downloading for offline use...