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

Unionf Find は競技プログラミングでは基本的なアルゴリズムなので, 説明は蟻本またはこのスライドにゆずる.
各クエリの計算量は数学的には解析が難しいが, 実用上は定数と考えて問題ない.
(計算量の細かい話)
計算量は $m(\ge n)$ 回の Find 操作, $n$ 回の Union 操作のクエリ列を処理するのに $\O (n + m \alpha(m, n))$ 時間であることが証明されている(後の解析で $\O (n + m \alpha(m + n, n))$ 時間に落ちることがわかっている).
ここで $\alpha(m, n)$ はアッカーマン関数 $A(i, j)$ を用いて以下のように定義される.
まず増加の非常に急激な関数であるアッカーマン関数は $A(i, j)$ は以下のように再帰的に定義される.
$A(1, j) = 2^j (j \ge 1)$, $A(i, 1) = A(i - 1, 2) (i \ge 2)$, $A(i, j) = A(i - 1, A(i, j - 1)) (i, j \ge 2)$
このとき $\alpha(m, n) = \min \{ i \ge 1 \mid A(i, 4 \lceil m / n \rceil) > \log n \}$ と定義される. これを見ると $m = \Omega(n \log \log n)$ で $\alpha(m, n) = 1$, $m = \Omega(n \log^* n)$ で $\alpha(m, n) \le 2$ みたいなことが分かり,
要をするにアッカーマン関数の逆関数 $\alpha(m, n)$ は実用上定数と考えてよい..
次に $a(i, n) = \min \{ j \ge 1 \mid A(i, j) > \log n \}$ を定義する.
このとき任意の正整数 $k$(定数) について $m (\ge n a(k, n))$ 回の Find 操作, $n$ 回の Union 操作のクエリ列を処理するのにかかる時間は $\O (m)$ time であることも言える($\alpha(n a(k, n), n) \le k$ より).
Union Find の計算量の解析の論文としては "Efficiency of a Good But Not Linear Set Union Algorithm" [Tarjan 1975] や "Worst-Case Analysis of Set Union Algorithms" [Tarjan, LEEUWEN 1984] が詳しい.
過去に上記論文の簡易版として Union Find の計算量についての記事を昔書きました. 簡単ではないので興味のある方は読んでみてください.
U-TOKYO AP Advent Calendar 2017 8 日目: Union Find の計算量の話
時間計算量: Find クエリ, Union クエリ ならし $\O (\alpha(m, n))$ ($\alpha(m, n)$ は上記で定義された増加の非常にゆるやかな関数. 実用上は定数と考えて良い.)
class UnionFind:
def __init__(self, node_size):
self._node = node_size
self.par = [i for i in range(self._node)]
self.size_ = [1] * self._node
def find(self, ver):
if self.par[ver] == ver:
return ver
else:
self.par[ver] = self.find(self.par[ver])
return self.par[ver]
def unite(self, ver1, ver2):
ver1, ver2 = self.find(ver1), self.find(ver2)
if ver1 == ver2:
return
if self.size_[ver1] < self.size_[ver2]:
ver1, ver2 = ver2, ver1
self.par[ver2] = ver1
self.size_[ver1] += self.size_[ver2]
def size(self, ver):
ver = self.find(ver)
return self.size_[ver]
def same(self, ver1, ver2):
return self.find(ver1) == self.find(ver2)
if __name__ == '__main__':
n, m = map(int, sys.stdin.readline().split())
uf = UnionFind(n)
for i in range(m):
s, t = map(int, sys.stdin.readline().split())
uf.unite(s, t)
q = int(sys.stdin.readline())
for i in range(q):
s, t = map(int, sys.stdin.readline().split())
if uf.same(s, t):
print("yes")
else:
print("no")
AOJ : Connected Components 提出コード