$\newcommand{\O}{\mathrm{O}}$

Unionf Find は競技プログラミングでは基本的なアルゴリズムなので, 説明は蟻本またはこのスライドにゆずる.
各クエリの計算量は数学的には解析が難しいが, 実用上は定数と考えて問題ない.
時間計算量: Find クエリ, Union クエリ ならし $\O (\alpha(m, n))$ ($\alpha(m, n)$ は上記で定義された増加の非常にゆるやかな関数. 実用上は定数と考えて良い.)
class UnionFind {
private:
int sz;
vector<int> par, size_;
public:
UnionFind(){}
UnionFind(int node_size) : sz(node_size), par(sz), size_(sz, 1){
iota(par.begin(), par.end(), 0);
}
int find(int x){
if(par[x] == x) return x;
else return par[x] = find(par[x]);
}
void unite(int x,int y){
x = find(x), y = find(y);
if(x == y) return;
if(size_[x] < size_[y]) swap(x,y);
par[y] = x;
size_[x] += size_[y];
}
int size(int x){
x = find(x);
return size_[x];
}
bool same(int x,int y){
return find(x) == find(y);
}
};
class UnionFind {
private:
vector<int> par;
public:
UnionFind(){}
UnionFind(const int node_size) : par(node_size){
iota(par.begin(), par.end(), 0);
}
// 普通の path compression
int find(int x){
if(par[x] == x) return x;
else return par[x] = find(par[x]);
}
// 実際に意味のある unite が行われたかどうかを返す.
bool unite(int x, int y){
int z;
while(par[x] != par[y]){
if(par[x] > par[y]) swap(x, y);
z = par[x], par[x] = par[y];
if(x == z) return true;
x = z;
}
return false;
}
// 普通の path compression
bool same(int x, int y){
return find(x) == find(y);
}
};
AOJ : Connected Components 提出コード