acl_cpp.dsu

dsu.dsu

# dsu
from acl_cpp.dsu import dsu

無向グラフに対して、

  • 辺の追加

  • \(2\) 頂点が連結かの判定

をならし \(O(\alpha(n))\) 時間で処理することが出来ます。

ここで、\(\alpha(n)\) はアッカーマン関数の逆関数で、ほとんど定数時間とみなせます。

また、内部的に各連結成分ごとに代表となる頂点を \(1\) つ持っています。辺の追加により連結成分がマージされる時、新たな代表元は元の連結成分の代表元のうちどちらかになります。

コンストラクタ

# dsu::dsu(int n)
def dsu(n: int = 0) -> dsu
  • \(n\) 頂点 \(0\) 辺の無向グラフを作ります。

制約

  • \(0 \le n \lt 2^{31}\)

計算量

  • \(O(n)\)

dsu.merge

# void dsu::merge(int a, int b)
def dsu.merge(a: int, b: int) -> None

\((a, b)\) を足します。

\(a, b\) が連結だった場合はその代表元、非連結だった場合は新たな代表元を返します。

制約

  • \(0 \le a \lt n\)

  • \(0 \le b \lt n\)

計算量

  • ならし \(O(\alpha(n))\)

dsu.same

# bool dsu::same(int a, int b)
def dsu.same(a: int, b: int) -> bool

頂点 \(a, b\) が連結かどうかを返します。

制約

  • \(0 \le a \lt n\)

  • \(0 \le b \lt n\)

計算量

  • ならし \(O(\alpha(n))\)

dsu.leader

# int dsu::leader(int a)
def dsu.leader(a: int) -> int

頂点 \(a\) の属する連結成分の代表元を返します。

制約

  • \(0 \le a \lt n\)

計算量

  • ならし \(O(\alpha(n))\)

dsu.size

# int dsu::size(int a)
def dsu.size(a: int) -> int

頂点 \(a\) の属する連結成分のサイズを返します。

制約

  • \(0 \le a \lt n\)

計算量

  • ならし \(O(\alpha(n))\)

dsu.groups

# vector<vector<int>> dsu::groups()
def dsu.groups() -> list[list[int]]

グラフを連結成分に分け、その情報を返します。

返り値は「「一つの連結成分の頂点番号のリスト」のリスト」です。 (内側外側限らず)vector 内でどの順番で頂点が格納されているかは未定義です。

計算量

  • \(O(n)\)

使用例

AC code of https://atcoder.jp/contests/practice2/tasks/practice2_a

from acl_cpp.dsu import dsu

N, Q = map(int, input().split())
d = dsu(N)

for _ in range(Q):
    t, u, v = map(int, input().split())
    if t == 0:
        d.merge(u, v)
    else:
        print(int(d.same(u, v)))