Union Find Tree
概要
Union Find Tree はデータを互いに素な集合に分割して保持することで以下の2つの操作を効率的に行えるデータ構造.
- Union: 2つの集合を1つに統合する
- Find: 特定の要素がどの集合に属しているか求める
Union Find Tree は素集合データ構造 (disjoint-set data structure) とも呼ばれている.
計算量
Snippet
C++
cpp
struct UnionFind {
std::vector<int> parent_or_size;
int cnt;
UnionFind(int n) : parent_or_size(n, -1), cnt(n) {}
void unite(int x, int y) {
x = find_root(x);
y = find_root(y);
if (x == y) {
return;
}
if (-parent_or_size[x] < -parent_or_size[y]) {
std::swap(x, y);
}
parent_or_size[x] += parent_or_size[y];
parent_or_size[y] = x;
cnt--;
}
bool is_same_root(int x, int y) { return find_root(x) == find_root(y); }
int find_root(int x) {
if (parent_or_size[x] < 0) {
return x;
}
return parent_or_size[x] = find_root(parent_or_size[x]);
}
int size(int x) { return -parent_or_size[find_root(x)]; }
};
Python
python
class UnionFind:
def __init__(self, n):
self.parent_or_size = [-1 for _ in range(n)]
self.cnt = n
def unite(self, x, y):
x, y = self.find_root(x), self.find_root(y)
if x == y:
return
if -self.parent_or_size[x] < -self.parent_or_size[y]:
x, y = y, x
self.parent_or_size[x] += self.parent_or_size[y]
self.parent_or_size[y] = x
self.cnt -= 1
def is_same_root(self, x, y):
return self.find_root(x) == self.find_root(y)
def find_root(self, x):
if self.parent_or_size[x] < 0:
return x
self.parent_or_size[x] = self.find_root(self.parent_or_size[x])
return self.parent_or_size[x]
def size(self, x):
return -self.parent_or_size[self.find_root(x)]
解説
初期状態は頂点数が
unite(x, y)
: 頂点 x と y が属する2つの集合を1つにマージするis_same_root(x, y)
: 頂点 x と y が同じ集合に属するかを判定するfind_root(x)
: 頂点 x が属する集合の根 (代表元) を返すsize(x)
: 頂点 x が属する集合のサイズを返すcnt
: グラフの連結成分の個数(集合の個数)
Union Find Tree には集合の結合はできても分割はできないという性質がある.
検証
- AOJ-DPL1-A: Disjoint Set: Union Find Tree
- ATC001-B: Union Find
- ABC120-D: Decayed Bridges
- ABC126-E: 1 or 2
- ABC157-D: Friend Suggestions
- ABC177-D: Friends
- ABC214-D: Sum of Maximum Weights
- ABC217-D: Cutting Woods
- ABC229-E: Graph Destruction
- ICPC模擬国内予選2020-B: 爆発の連鎖
- ICPC国内予選2020-B: 追跡調査
参考文献
- プログラミングコンテストチャレンジブック