This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/scc"
#include "../Library/Template.hpp"
#include "../Library/Graph/StronglyConnectedComponents.hpp"
int main(){
cin.tie(0)->sync_with_stdio(false);
int N, M; cin >> N >> M;
auto G = InputGraph(N, M, 0, false, true);
StronglyConnectedComponents scc(G);
cout << scc.ComponentCount() << '\n';
for(const auto &vs : scc.Components()){
cout << vs.size();
for(const auto &v : vs){
cout << ' ' << v;
}
cout << '\n';
}
}#line 1 "verify/LC-StronglyConnectedComponents.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/scc"
#line 2 "Library/Template.hpp"
#line 2 "Library/Common.hpp"
/**
* @file Common.hpp
*/
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
using ll = int64_t;
using ull = uint64_t;
constexpr const ll INF = (1LL << 62) - (3LL << 30) - 1;
#line 4 "Library/Template.hpp"
inline bool YnPrint(bool flag){cout << (flag ? "Yes" : "No") << '\n'; return flag;}
inline bool YNPrint(bool flag){cout << (flag ? "YES" : "NO") << '\n'; return flag;}
template<typename Container>
inline void Sort(Container &container){sort(container.begin(), container.end());}
template<typename Container>
inline void ReverseSort(Container &container){sort(container.rbegin(), container.rend());}
template<typename Container>
inline void Reverse(Container &container){reverse(container.begin(), container.end());}
template<typename Value>
inline int PopCount(const Value &value){return __builtin_popcount(value);}
template<typename Value>
inline Value Floor(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator < 0 ? (numerator + 1) / denominator - 1 : numerator / denominator;}
template<typename Value>
inline Value Ceil(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator > 0 ? (numerator - 1) / denominator + 1 : numerator / denominator;}
template<typename Value>
inline int LowerBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), lower_bound(container.begin(), container.end(), value));}
template<typename Value>
inline int UpperBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), upper_bound(container.begin(), container.end(), value));}
template<typename Value>
inline bool Between(const Value &lower, const Value &x, const Value &higher){return lower <= x && x <= higher;}
template<typename Value>
inline bool InGrid(const Value &y, const Value &x, const Value &ymax, const Value &xmax){return Between(0, y, ymax - 1) && Between(0, x, xmax - 1);}
template<typename Value>
inline Value Median(const Value &a, const Value &b, const Value &c){return Between(b, a, c) || Between(c, a, b) ? a : (Between(a, b, c) || Between(c, b, a) ? b : c);}
template<typename Value>
inline Value Except(Value &src, Value &cond, Value &excp){return (src == cond ? excp : src);}
template<class Value>
bool chmin(Value &src, const Value &cmp){if(src > cmp){src = cmp; return true;} return false;}
template<class Value>
bool chmax(Value &src, const Value &cmp){if(src < cmp){src = cmp; return true;} return false;}
template<typename Value>
inline Value min(vector<Value> &v){return *min_element((v).begin(), (v).end());}
template<typename Value>
inline Value max(vector<Value> &v){return *max_element((v).begin(), (v).end());}
const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};
vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
vector<pair<int, int>> ret;
for(int d = 0; d < 4 * (1 + dir_8); ++d){
int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
if(InGrid(next_y, next_x, max_y, max_x)){
ret.emplace_back(next_y, next_x);
}
}
return ret;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
os << p.first << " " << p.second;
return os;
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
is >> p.first >> p.second;
return is;
}
template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
for (int i = 0; i < v.size(); ++i){
os << v[i] << (i + 1 != v.size() ? " " : "");
}
return os;
}
template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
for (int i = 0; i < v.size(); ++i){
os << v[i] << (i + 1 != v.size() ? "\n" : "");
}
return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
for (int i = 0; i < v.size(); ++i) is >> v[i];
return is;
}
template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
for (auto &u : v){
os << u << " ";
}
return os;
}
template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
assert(v1.size() == v2.size());
vector<pair<T1, T2>> v;
for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
return v;
}
template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
vector<T1> v1;
vector<T2> v2;
transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
return {v1, v2};
}
template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
vector<T1> v1;
vector<T2> v2;
vector<T3> v3;
transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
return {v1, v2, v3};
}
template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
vector<pair<T1, T2>> v(size);
for(auto &[p, q] : v) cin >> p >> q;
return DisassembleVectorPair(v);
}
template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
vector<tuple<T1, T2, T3>> v(size);
for(auto &[p, q, r] : v) cin >> p >> q >> r;
return DisassembleVectorTuple(v);
}
#line 2 "Library/Graph/Graph.hpp"
#line 4 "Library/Graph/Graph.hpp"
using Vertex = int;
template<typename WeightType = int32_t>
struct Edge{
public:
Edge() = default;
Edge(Vertex from_, Vertex to_, WeightType weight_ = 1, int idx_ = -1) :
from(from_), to(to_), cost(weight_), idx(idx_){}
bool operator<(const Edge<WeightType> &e) const {return cost < e.cost;}
operator int() const {return to;}
Vertex from, to;
WeightType cost;
int idx;
};
template<typename WeightType = int32_t>
class Graph{
public:
Graph() = default;
Graph(int V) : edge_size_(0), adjacent_list_(V){}
inline void AddUndirectedEdge(Vertex u, Vertex v, WeightType w = 1){
int idx = edge_size_++;
adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
adjacent_list_[v].push_back(Edge<WeightType>(v, u, w, idx));
}
inline void AddDirectedEdge(Vertex u, Vertex v, WeightType w = 1){
int idx = edge_size_++;
adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
}
inline size_t VertexSize() const {
return adjacent_list_.size();
}
inline size_t EdgeSize() const {
return edge_size_;
}
inline vector<Edge<WeightType>> &operator[](const Vertex v){
return adjacent_list_[v];
}
inline const vector<Edge<WeightType>> &operator[](const Vertex v) const {
return adjacent_list_[v];
}
private:
size_t edge_size_;
vector<vector<Edge<WeightType>>> adjacent_list_;
};
template<typename WeightType = int32_t>
Graph<WeightType> InputGraph(int N, int M, int padding = -1, bool weighted = false, bool directed = false){
Graph<WeightType> G(N);
for(int i = 0; i < M; ++i){
Vertex u, v; WeightType w = 1;
cin >> u >> v, u += padding, v += padding;
if(weighted) cin >> w;
if(directed) G.AddDirectedEdge(u, v, w);
else G.AddUndirectedEdge(u, v, w);
}
return G;
}
#line 2 "Library/Graph/GraphMisc.hpp"
#line 4 "Library/Graph/GraphMisc.hpp"
template<typename WeightType>
vector<Edge<WeightType>> ConvertEdgeSet(const Graph<WeightType> &G){
vector<Edge<WeightType>> ret;
vector<bool> check(G.EdgeSize(), false);
int n = G.VertexSize();
for(int u = 0; u < n; ++u){
for(const Edge<WeightType> &e : G[u]){
if(check[e.idx]) continue;
check[e.idx] = true;
ret.push_back(e);
}
}
return ret;
}
template<typename WeightType>
vector<vector<WeightType>> ConvertDistanceMatrix(const Graph<WeightType> &G){
int n = G.VertexSize();
vector<vector<WeightType>> ret(n, vector<WeightType>(n, WeightType(INF)));
for(int u = 0; u < n; ++u){
ret[u][u] = WeightType(0);
for(const Edge<WeightType> &e : G[u]){
ret[u][e.to] = e.cost;
}
}
return ret;
}
template<typename WeightType>
Graph<WeightType> ReverseGraph(const Graph<WeightType> &G){
int n = G.VertexSize();
Graph<WeightType> ret(n);
for(int u = 0; u < n; ++u){
for(const Edge<WeightType> &e : G[u]){
ret.AddDirectedEdge(e.to, e.from, e.cost);
}
}
return ret;
}
#line 3 "Library/Graph/StronglyConnectedComponents.hpp"
template<typename WeightType>
struct StronglyConnectedComponents{
public:
StronglyConnectedComponents(Graph<WeightType> &graph) :
G(graph), RG(ReverseGraph(graph)), V(G.VertexSize()), belong_(V, -1){
vector<int> label(V, -1);
vector<bool> state(V, false);
int nex = 0;
vector<Vertex> vs(V);
iota(vs.begin(), vs.end(), 0);
for(auto v : vs){
if(!state[v]) dfs1(v, label, nex, state);
}
sort(vs.begin(), vs.end(), [&](Vertex u, Vertex v){
return label[u] > label[v];
});
for(auto v : vs){
if(state[v]){
int c = components_.size();
components_.push_back(vector<Vertex>{});
dfs2(v, label, c, state);
}
}
}
inline vector<vector<Vertex>> &Components(){
return components_;
}
inline int ComponentCount() const {
return (int)components_.size();
}
inline int BelongComponent(const Vertex &v) const {
return belong_[v];
}
vector<Vertex> TopologicalSort() const {
vector<Vertex> ret;
for(const auto &vs : components_){
for(const auto &v : vs){
ret.emplace_back(v);
}
}
return ret;
}
Graph<WeightType> ContractedGraph() const {
int nn = ComponentCount();
Graph<WeightType> ret(nn);
for(int u = 0; u < V; ++u){
int nu = BelongComponent(u);
for(const Edge<WeightType> &e : G[u]){
int nv = BelongComponent(e.to);
if(nu == nv) continue;
ret.AddDirectedEdge(nu, nv, e.cost);
}
}
return ret;
}
inline int operator[](const Vertex &v){
return BelongComponent(v);
}
inline const int operator[](const Vertex &v) const {
return BelongComponent(v);
}
private:
Graph<WeightType> &G;
Graph<WeightType> RG;
int V;
vector<vector<Vertex>> components_;
vector<int> belong_;
void dfs1(Vertex v, vector<int> &label, int &nex, vector<bool> &state){
state[v] = true;
for(const Edge<WeightType> &e : G[v]){
if(state[e.to]) continue;
dfs1(e.to, label, nex, state);
}
label[v] = nex++;
return;
}
void dfs2(Vertex v, vector<int> &label, int component, vector<bool> &state){
components_[component].push_back(v);
belong_[v] = component;
state[v] = false;
for(const Edge<WeightType> &e : RG[v]){
if(!state[e.to]) continue;
dfs2(e.to, label, component, state);
}
return;
}
};
#line 5 "verify/LC-StronglyConnectedComponents.test.cpp"
int main(){
cin.tie(0)->sync_with_stdio(false);
int N, M; cin >> N >> M;
auto G = InputGraph(N, M, 0, false, true);
StronglyConnectedComponents scc(G);
cout << scc.ComponentCount() << '\n';
for(const auto &vs : scc.Components()){
cout << vs.size();
for(const auto &v : vs){
cout << ' ' << v;
}
cout << '\n';
}
}