This documentation is automatically generated by online-judge-tools/verification-helper
#include "src/graph/StronglyConnectedComponents.hpp"有向グラフを強連結成分に分解する. 各強連結成分の番号は強連結成分を 1 つの頂点にするように縮約した DAG におけるトポロジカル順序を同時に表す. 実装は Tarjan の考案したアルゴリズムに沿っている.
| メンバ関数 | 効果 | 時間計算量 |
|---|---|---|
StronglyConnectedComponents(n) |
$n$ 頂点 $0$ 辺のグラフとして初期化する. | $O(n)$ |
add_edge(u, v) |
頂点 $u$ から頂点 $v$ への有向辺を追加する. | $O(1)$ |
build() |
強連結成分分解, 各強連結成分の頂点集合を返す. | $O(n + m)$ |
make_graph() |
各強連結成分を頂点とする DAG の辺情報を返す. | $O(n + m + m \log m)$ |
make_graph では利便性を考えてソートして多重辺を除去しているが,特にその必要もなく時間計算量が問題であればこのパートは除いて良い.
#pragma once
#include <algorithm>
#include <cassert>
#include <vector>
struct StronglyConnectedComponents {
std::vector<std::vector<int>> G;
std::vector<int> comp; // component id vertex v belongs to
StronglyConnectedComponents(int n) : G(n), comp(n, -1), n(n), time(0), group_num(0), ord(n, -1), low(n) {}
void add_edge(int u, int v) {
assert(0 <= u && u < n);
assert(0 <= v && v < n);
G[u].emplace_back(v);
}
int add_vertex() {
G.emplace_back();
comp.emplace_back(-1);
ord.emplace_back(-1);
low.emplace_back();
return n++;
}
std::vector<std::vector<int>> build() {
for (int i = 0; i < n; i++) {
if (ord[i] < 0) {
dfs(i);
}
}
for (int& x : comp) x = group_num - 1 - x;
std::vector<std::vector<int>> groups(group_num);
for (int i = 0; i < n; i++) groups[comp[i]].emplace_back(i);
return groups;
}
std::vector<std::vector<int>> make_graph() {
std::vector<std::vector<int>> dag(group_num);
for (int v = 0; v < n; v++) {
for (int& u : G[v]) {
if (comp[v] != comp[u]) {
dag[comp[v]].emplace_back(comp[u]);
}
}
}
for (auto& to : dag) {
std::sort(to.begin(), to.end());
to.erase(unique(to.begin(), to.end()), to.end());
}
return dag;
}
int operator[](int v) const { return comp[v]; }
private:
int n, time, group_num;
std::vector<int> ord, low, visited;
void dfs(int v) {
ord[v] = low[v] = time++;
visited.emplace_back(v);
for (int& u : G[v]) {
if (ord[u] == -1) {
dfs(u);
low[v] = std::min(low[v], low[u]);
} else if (comp[u] < 0) {
low[v] = std::min(low[v], ord[u]);
}
}
if (ord[v] == low[v]) {
while (true) {
int u = visited.back();
visited.pop_back();
comp[u] = group_num;
if (u == v) break;
}
group_num++;
}
}
};#line 2 "src/graph/StronglyConnectedComponents.hpp"
#include <algorithm>
#include <cassert>
#include <vector>
struct StronglyConnectedComponents {
std::vector<std::vector<int>> G;
std::vector<int> comp; // component id vertex v belongs to
StronglyConnectedComponents(int n) : G(n), comp(n, -1), n(n), time(0), group_num(0), ord(n, -1), low(n) {}
void add_edge(int u, int v) {
assert(0 <= u && u < n);
assert(0 <= v && v < n);
G[u].emplace_back(v);
}
int add_vertex() {
G.emplace_back();
comp.emplace_back(-1);
ord.emplace_back(-1);
low.emplace_back();
return n++;
}
std::vector<std::vector<int>> build() {
for (int i = 0; i < n; i++) {
if (ord[i] < 0) {
dfs(i);
}
}
for (int& x : comp) x = group_num - 1 - x;
std::vector<std::vector<int>> groups(group_num);
for (int i = 0; i < n; i++) groups[comp[i]].emplace_back(i);
return groups;
}
std::vector<std::vector<int>> make_graph() {
std::vector<std::vector<int>> dag(group_num);
for (int v = 0; v < n; v++) {
for (int& u : G[v]) {
if (comp[v] != comp[u]) {
dag[comp[v]].emplace_back(comp[u]);
}
}
}
for (auto& to : dag) {
std::sort(to.begin(), to.end());
to.erase(unique(to.begin(), to.end()), to.end());
}
return dag;
}
int operator[](int v) const { return comp[v]; }
private:
int n, time, group_num;
std::vector<int> ord, low, visited;
void dfs(int v) {
ord[v] = low[v] = time++;
visited.emplace_back(v);
for (int& u : G[v]) {
if (ord[u] == -1) {
dfs(u);
low[v] = std::min(low[v], low[u]);
} else if (comp[u] < 0) {
low[v] = std::min(low[v], ord[u]);
}
}
if (ord[v] == low[v]) {
while (true) {
int u = visited.back();
visited.pop_back();
comp[u] = group_num;
if (u == v) break;
}
group_num++;
}
}
};