結果
問題 |
No.3200 Sinking Islands
|
ユーザー |
|
提出日時 | 2025-07-03 16:47:22 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 527 ms / 2,000 ms |
コード長 | 3,740 bytes |
コンパイル時間 | 357 ms |
コンパイル使用メモリ | 82,152 KB |
実行使用メモリ | 106,108 KB |
最終ジャッジ日時 | 2025-07-03 16:52:04 |
合計ジャッジ時間 | 11,098 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 20 |
ソースコード
# f.py import sys class DSU: """ DSU (Disjoint Set Union) または Union-Find データ構造。 経路圧縮 (Path Compression) とサイズによる結合 (Union by Size) を実装しています。 """ def __init__(self, n: int): """ Args: n (int): 要素の数。0からnまでのn+1個の要素を初期化します。 """ # 各要素の親を格納するリスト。最初は自身が親。 self.parent = list(range(n + 1)) # 各集合のサイズを格納するリスト self.sz = [1] * (n + 1) def find(self, i: int) -> int: """ 要素iが属する集合の代表元(ルート)を探します。 経路圧縮を行い、計算量を削減します。 Args: i (int): 探す対象の要素。 Returns: int: 要素iが属する集合の代表元。 """ if self.parent[i] == i: return i self.parent[i] = self.find(self.parent[i]) return self.parent[i] def unite(self, i: int, j: int): """ 要素iが属する集合と要素jが属する集合を併合します。 サイズが小さい方の木を大きい方の木に結合します(Union by Size)。 Args: i (int): 併合する要素1。 j (int): 併合する要素2。 """ root_i = self.find(i) root_j = self.find(j) if root_i != root_j: if self.sz[root_i] < self.sz[root_j]: root_i, root_j = root_j, root_i self.parent[root_j] = root_i self.sz[root_i] += self.sz[root_j] def f_solver(): """ メインの処理。 """ # 高速入出力 input = sys.stdin.readline N, M = map(int, input().split()) edges = [tuple(map(int, input().split())) for _ in range(M)] Q = int(input()) # クエリで指定された辺のインデックスを0-indexedで読み込む query_edges = [int(input()) - 1 for _ in range(Q)] # クエリで削除される辺をマーク is_removed = [False] * M for edge_idx in query_edges: is_removed[edge_idx] = True # DSUをN個の頂点で初期化 dsu = DSU(N) # クエリで削除されない辺を使って、初期の連結成分を構築 for i in range(M): if not is_removed[i]: u, v = edges[i] dsu.unite(u, v) # 初期の非連結ペアの数を計算 current_disconnected_pairs = 0 visited_root = [False] * (N + 1) connected_nodes = 0 for i in range(1, N + 1): root = dsu.find(i) if not visited_root[root]: size = dsu.sz[root] # 現在の連結成分のノードと、まだ訪れていないノードとのペア数を加算 current_disconnected_pairs += size * (N - connected_nodes - size) connected_nodes += size visited_root[root] = True # クエリを逆順に処理(削除された辺を元に戻していく) ans = [0] * Q for i in range(Q - 1, -1, -1): ans[i] = current_disconnected_pairs edge_idx = query_edges[i] u, v = edges[edge_idx] root_u = dsu.find(u) root_v = dsu.find(v) # 辺を追加することで異なる連結成分が1つになる場合、 # 非連結ペアの数は (成分uのサイズ * 成分vのサイズ) だけ減少する if root_u != root_v: current_disconnected_pairs -= dsu.sz[root_u] * dsu.sz[root_v] dsu.unite(u, v) # 答えをまとめて出力 for val in ans: print(val) if __name__ == '__main__': f_solver()