-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b48cffb
commit b417edf
Showing
2 changed files
with
101 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#pragma once | ||
|
||
#include <algorithm> | ||
#include <tuple> | ||
#include <utility> | ||
#include <vector> | ||
|
||
#include "graph/strongly_connected_components.hpp" | ||
|
||
// edges[i] = (s, t) means that the edge (s, t) is added at i-th tick. | ||
// Return the earliest tick when the edge (s, t) is included in a cycle. | ||
// If the edge (s, t) is never included in a cycle or s == t, return M. | ||
// Complexity: O(M log M), where M = edges.size() | ||
// Verified: https://codeforces.com/contest/1989/submission/268026664 | ||
std::vector<int> incremental_scc(const std::vector<std::pair<int, int>> &edges) { | ||
int N = 1; | ||
for (auto [s, t] : edges) N = std::max({N, s + 1, t + 1}); | ||
|
||
const int M = edges.size(); | ||
|
||
std::vector<int> ret(M, M); | ||
|
||
std::vector<int> compressed_idx(N, -1); | ||
|
||
using Edges = std::vector<std::tuple<int, int, int>>; | ||
|
||
auto rec = [&](auto &&self, const Edges &e, int tl, int tr) -> void { | ||
if (e.empty() or tl + 1 == tr) return; | ||
|
||
int n = 0; | ||
for (const auto &[tick, s, t] : e) { | ||
if (compressed_idx.at(s) == -1) compressed_idx.at(s) = n++; | ||
if (compressed_idx.at(t) == -1) compressed_idx.at(t) = n++; | ||
} | ||
|
||
const int tmid = (tl + tr) / 2; | ||
|
||
DirectedGraphSCC scc(n); | ||
for (const auto &[tick, s, t] : e) { | ||
if (tick < tmid) scc.add_edge(compressed_idx.at(s), compressed_idx.at(t)); | ||
} | ||
scc.FindStronglyConnectedComponents(); | ||
|
||
Edges left, right; | ||
|
||
for (const auto &[tick, s, t] : e) { | ||
const int sc = compressed_idx.at(s), tc = compressed_idx.at(t); | ||
if (tick < tmid and scc.cmp.at(sc) == scc.cmp.at(tc)) { | ||
ret.at(tick) = tmid - 1; | ||
left.emplace_back(tick, sc, tc); | ||
} else { | ||
right.emplace_back(tick, scc.cmp.at(sc), scc.cmp.at(tc)); | ||
} | ||
} | ||
|
||
for (auto [_, s, t] : e) compressed_idx.at(s) = compressed_idx.at(t) = -1; | ||
|
||
self(self, left, tl, tmid); | ||
self(self, right, tmid, tr); | ||
}; | ||
|
||
Edges init; | ||
init.reserve(M); | ||
for (int tick = 0; tick < M; ++tick) { | ||
if (auto [s, t] = edges.at(tick); s != t) init.emplace_back(tick, s, t); | ||
} | ||
|
||
rec(rec, init, 0, M + 1); | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
title: Incremental SCC (強連結成分) | ||
documentation_of: ./incremental_scc.hpp | ||
--- | ||
|
||
$m$ 個の有向辺からなる列が与えられ,先頭の要素から順にグラフに追加していく.各有向辺について,グラフに何番目の辺まで追加したときに初めてその辺を含む閉路ができるかを $O(m \log m)$ で計算する. | ||
|
||
この処理は以下のような用途に使える. | ||
|
||
- UnionFind などのデータ構造を併用することで,各時点での強連結成分を管理できる. | ||
- 各辺を含む閉路ができる時刻を重みとして最小全域木を求め,更に heavy-light decomposition やセグメント木と併用することで, 2 頂点が同一の強連結成分に初めて属する時刻をクエリ $O(n \log n)$ 等で計算できる. | ||
|
||
## 使用方法 | ||
|
||
```cpp | ||
vector<pair<int, int>> edges; // 有向辺の列. edges[i] は時刻 i に追加される | ||
|
||
auto ticks = incremental_scc(edges); | ||
|
||
assert(ticks.size() == edges.size()); | ||
// ticks[i] = (edges[i] を含む閉路ができる時刻 (0 <= ticks[i] < m)) または m (閉路ができない場合・自己ループの場合) | ||
``` | ||
## 問題例 | ||
- [Educational Codeforces Round 167 (Rated for Div. 2) F. Simultaneous Coloring](https://codeforces.com/contest/1989/problem/F) | ||
## リンク | ||
- [My own algorithm — offline incremental strongly connected components in O(m*log(m)) - Codeforces](https://codeforces.com/blog/entry/91608) |