a01sa01to's competitive programming library. Requires C++20 or higher with GCC. This documentation is automatically generated by online-judge-tools/verification-helper
#include "library/graph/scc.hpp"強連結成分分解する。
scc(T adj_list) -> vector<vector<int>>:
強連結成分分解を行い、「頂点のリスト」のリストを返す。トポロジカルソートされる。 $O(n + m)$#pragma once
#include <cassert>
#include <functional>
#include <ranges>
#include <vector>
using namespace std;
#include "../_internal/graph-base.hpp"
namespace asalib::graph {
template<_internal::adjacency_list T>
vector<vector<int>> scc(const T& adj_list) {
const int n_vertex = ranges::ssize(adj_list);
vector adj_list_rev(n_vertex, vector<int>());
for (int v = 0; v < n_vertex; ++v) {
for (const int& u : adj_list[v]) {
assert(u < n_vertex);
adj_list_rev[u].emplace_back(v);
}
}
constexpr int Unvisited = -1;
vector visited(n_vertex, false);
int order_num = 0;
vector ord2pt(n_vertex, Unvisited);
function<void(int)> visit1 = [&](int v) {
visited[v] = true;
for (const int& w : adj_list[v]) {
if (!visited[w]) visit1(w);
}
ord2pt[order_num++] = v;
};
for (int v = 0; v < n_vertex; ++v) {
if (!visited[v]) visit1(v);
}
visited.assign(n_vertex, false);
int comp_num = 0;
vector comp(n_vertex, Unvisited);
function<void(int)> visit2 = [&](int v) {
visited[v] = true;
for (const int& w : adj_list_rev[v]) {
if (!visited[w]) visit2(w);
}
comp[v] = comp_num;
};
for (int i = n_vertex - 1; i >= 0; --i) {
if (!visited[ord2pt[i]]) visit2(ord2pt[i]), ++comp_num;
}
vector<vector<int>> res(comp_num);
for (int v = 0; v < n_vertex; ++v) {
res[comp[v]].emplace_back(v);
}
return res;
}
} // namespace asalib::graph#line 2 "library/graph/scc.hpp"
#include <cassert>
#include <functional>
#include <ranges>
#include <vector>
using namespace std;
#line 2 "library/_internal/graph-base.hpp"
#include <concepts>
#line 5 "library/_internal/graph-base.hpp"
#include <utility>
using namespace std;
namespace asalib::_internal {
// vector<vector<int>> とかの隣接リストを表す型
template<class T>
concept adjacency_list = requires(T t) {
ranges::ssize(t);
{ t[0] } -> ranges::range;
{ *ranges::begin(t[0]) } -> convertible_to<int>;
};
// 辺のリストを表す型
// 重み付きも考慮し pair<int, int> と tuple<int, int, int> の両方を許容
template<class T>
concept edge_list = requires(T t) {
ranges::ssize(t);
{ get<0>(t[0]) } -> convertible_to<int>;
{ get<1>(t[0]) } -> convertible_to<int>;
};
} // namespace asalib::_internal
#line 10 "library/graph/scc.hpp"
namespace asalib::graph {
template<_internal::adjacency_list T>
vector<vector<int>> scc(const T& adj_list) {
const int n_vertex = ranges::ssize(adj_list);
vector adj_list_rev(n_vertex, vector<int>());
for (int v = 0; v < n_vertex; ++v) {
for (const int& u : adj_list[v]) {
assert(u < n_vertex);
adj_list_rev[u].emplace_back(v);
}
}
constexpr int Unvisited = -1;
vector visited(n_vertex, false);
int order_num = 0;
vector ord2pt(n_vertex, Unvisited);
function<void(int)> visit1 = [&](int v) {
visited[v] = true;
for (const int& w : adj_list[v]) {
if (!visited[w]) visit1(w);
}
ord2pt[order_num++] = v;
};
for (int v = 0; v < n_vertex; ++v) {
if (!visited[v]) visit1(v);
}
visited.assign(n_vertex, false);
int comp_num = 0;
vector comp(n_vertex, Unvisited);
function<void(int)> visit2 = [&](int v) {
visited[v] = true;
for (const int& w : adj_list_rev[v]) {
if (!visited[w]) visit2(w);
}
comp[v] = comp_num;
};
for (int i = n_vertex - 1; i >= 0; --i) {
if (!visited[ord2pt[i]]) visit2(ord2pt[i]), ++comp_num;
}
vector<vector<int>> res(comp_num);
for (int v = 0; v < n_vertex; ++v) {
res[comp[v]].emplace_back(v);
}
return res;
}
} // namespace asalib::graph