OfflineDynamicConnectivity

OfflineDynamicConnectivity は、辺の追加・削除があるグラフを offline に処理するための helper です。

各辺が有効な時間区間 [l, r) をあらかじめ与えておき、各時刻 t のグラフ状態を RollbackDSU で復元しながら query を処理します。

使いどころ

次のような問題で使います。

考え方

辺 (u, v) が時刻区間 [l, r) で有効だとします。

時間軸 [0, q) に segment tree を作り、区間 [l, r) を覆う node にその辺を登録します。

その後、segment tree を DFS します。

こうすると、各辺は O(log q) 個の node にだけ登録され、各時刻の状態を効率よく復元できます。

import

import atcoder/extra/graph/offline_dynamic_connectivity

この module は rollback_dsu も re-export します。
callback 内では RollbackDSU の same, size, componentCount などをそのまま使えます。

型

type OfflineDCEdge = tuple[u, v: int]
type OfflineDynamicConnectivity

コンストラクタ

proc initOfflineDynamicConnectivity(n, q: int): OfflineDynamicConnectivity

辺の追加

proc addEdgeInterval(dc: var OfflineDynamicConnectivity, l, r, u, v: int)

無向辺 (u, v) が半開区間 [l, r) で有効であることを登録します。

実行

proc run(dc: OfflineDynamicConnectivity, f: proc(t: int, uf: RollbackDSU))
proc componentCounts(dc: OfflineDynamicConnectivity): seq[int]

使用例

var dc = initOfflineDynamicConnectivity(n = 4, q = 5)# t = 0: 0-1# t = 1: 0-1, 1-2# t = 2: 0-1, 1-2, 2-3# t = 3: 1-2, 2-3# t = 4: 1-2dc.addEdgeInterval(0, 3, 0, 1)dc.addEdgeInterval(1, 5, 1, 2)dc.addEdgeInterval(2, 4, 2, 3)var ans = newSeq[bool](5)dc.run(proc(t: int, uf: RollbackDSU) =  ans[t] = uf.same(0, 3))doAssert ans == @[false, false, true, false, false]

連結成分数だけなら、helper を使えます。

doAssert dc.componentCounts == @[3, 2, 1, 2, 3]

Nim らしい使い方

callback と UFCS を使うと、各時刻の query を自然に書けます。

dc.run(proc(t: int, uf: RollbackDSU) =
  echo t, ": ", uf.componentCount
)

計算量

時刻数を q、登録した有効区間数を m とします。

RollbackDSU は path compression を使わないため、merge / same / size は O(log n) 程度です。

注意

関連資料・他言語ライブラリ