This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/biconnected_components"
#include "graphs/BlockCut.cpp"
#include "Template.cpp"
using namespace lib;
int32_t main() {
iopt;
int n, m; cin >> n >> m;
graph::Graph<int> g(n);
for(int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
g.add_2edge(a, b);
}
auto bct = graph::make_block_cut(g);
cout << bct.n_components() << endl;
for(int i = 0; i < bct.n_components(); i++) {
const auto comp = bct.component(i);
cout << comp.size() << " ";
for(const auto v : comp) cout << v << " ";
cout << endl;
}
}
#line 1 "tests/yosupo/biconnected-components.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/biconnected_components"
#line 1 "graphs/BlockCut.cpp"
#include <bits/stdc++.h>
#line 1 "Graph.cpp"
#line 1 "Traits.cpp"
#line 4 "Traits.cpp"
namespace lib {
using namespace std;
namespace traits {
template <typename...> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
/// keep caide
template <typename Iterator>
using IteratorCategory = typename iterator_traits<Iterator>::iterator_category;
/// keep caide
template <typename Container>
using IteratorCategoryOf = IteratorCategory<typename Container::iterator>;
/// keep caide
template <typename Iterator>
using IteratorValue = typename iterator_traits<Iterator>::value_type;
/// keep caide
template <typename Container>
using IteratorValueOf = IteratorValue<typename Container::iterator>;
/// keep caide
template <typename Iterator>
using IsRandomIterator =
is_base_of<random_access_iterator_tag, IteratorCategory<Iterator>>;
/// keep caide
template <typename Iterator>
using IsInputIterator =
is_base_of<input_iterator_tag, IteratorCategory<Iterator>>;
/// keep caide
template <typename Iterator>
using IsBidirectionalIterator =
is_base_of<bidirectional_iterator_tag, IteratorCategory<Iterator>>;
/// keep caide
template <typename Container>
using HasRandomIterator =
is_base_of<random_access_iterator_tag, IteratorCategoryOf<Container>>;
/// keep caide
template <typename Container>
using HasInputIterator =
is_base_of<input_iterator_tag, IteratorCategoryOf<Container>>;
/// keep caide
template <typename Container>
using HasBidirectionalIterator =
is_base_of<bidirectional_iterator_tag, IteratorCategoryOf<Container>>;
} // namespace traits
} // namespace lib
#line 1 "utils/Wrappers.cpp"
#line 4 "utils/Wrappers.cpp"
namespace lib {
using namespace std;
namespace graph {
template <typename T> struct Edge {
const int from, to;
T data;
};
template <> struct Edge<void> { const int from, to; };
template <typename T> struct VertexWrapper { T data; };
template <> struct VertexWrapper<void> {};
} // namespace graph
} // namespace lib
#line 6 "Graph.cpp"
namespace lib {
using namespace std;
namespace graph {
template <typename V = void, typename E = void, bool Directed = false>
struct GraphImpl {
typedef GraphImpl<V, E> self_type;
typedef vector<vector<int>> adj_list;
typedef Edge<E> edge_type;
typedef VertexWrapper<V> vertex_type;
const static bool directed = Directed;
vector<edge_type> edges;
adj_list adj;
vector<vertex_type> vertices;
class iterator {
public:
typedef iterator self_type;
typedef edge_type value_type;
typedef edge_type &reference;
typedef edge_type *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
iterator(vector<int> *adj, vector<edge_type> *edges, int ptr = 0)
: adj_(adj), edges_(edges), ptr_(ptr) {}
self_type operator++() {
ptr_++;
return *this;
}
self_type operator++(int junk) {
self_type i = *this;
ptr_++;
return i;
}
reference operator*() { return (*edges_)[(*adj_)[ptr_]]; }
pointer operator->() { return &(*edges_)[(*adj_)[ptr_]]; }
bool operator==(const self_type &rhs) const {
return adj_ == rhs.adj_ && ptr_ == rhs.ptr_;
}
bool operator!=(const self_type &rhs) const { return !(*this == rhs); }
private:
vector<int> *adj_;
vector<edge_type> *edges_;
int ptr_;
};
class const_iterator {
public:
typedef const_iterator self_type;
typedef edge_type value_type;
typedef edge_type &reference;
typedef edge_type *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
const_iterator(vector<int> *adj, vector<edge_type> *edges, int ptr = 0)
: adj_(adj), edges_(edges), ptr_(ptr) {}
self_type operator++() {
ptr_++;
return *this;
}
self_type operator++(int junk) {
self_type i = *this;
ptr_++;
return i;
}
const value_type &operator*() { return (*edges_)[(*adj_)[ptr_]]; }
const value_type *operator->() { return &(*edges_)[(*adj_)[ptr_]]; }
bool operator==(const self_type &rhs) const {
return adj_ == rhs.adj_ && ptr_ == rhs.ptr_;
}
bool operator!=(const self_type &rhs) const { return !(*this == rhs); }
private:
vector<int> *adj_;
vector<edge_type> *edges_;
int ptr_;
};
struct iterable {
vector<int> *adj_;
vector<edge_type> *edges_;
iterable(vector<int> *adj, vector<edge_type> *edges)
: adj_(adj), edges_(edges) {}
inline iterator begin() { return iterator(adj_, edges_); }
inline iterator end() { return iterator(adj_, edges_, adj_->size()); }
inline const_iterator cbegin() const {
return const_iterator(adj_, edges_);
}
inline const_iterator cend() const {
return const_iterator(adj_, edges_, adj_->size());
}
inline const_iterator begin() const { return cbegin(); }
inline const_iterator end() const { return cend(); }
inline edge_type &operator[](int i) { return (*edges_)[(*adj_)[i]]; }
inline const edge_type &operator[](int i) const {
return (*edges_)[(*adj_)[i]];
}
inline int index(int i) const { return (*adj_)[i]; }
inline int size() const { return adj_->size(); }
};
GraphImpl() {}
template <typename S = V,
typename enable_if<is_void<S>::value>::type * = nullptr>
GraphImpl(size_t n) : adj(n) {}
template <typename S = V,
typename enable_if<!is_void<S>::value>::type * = nullptr>
GraphImpl(size_t n) : adj(n), vertices(n) {}
inline iterable n_edges(int i) { return iterable(&adj[i], &edges); }
inline const iterable n_edges(int i) const {
return iterable(const_cast<vector<int> *>(&adj[i]),
const_cast<vector<edge_type> *>(&edges));
}
inline int degree(int i) const { return adj[i].size(); }
inline int size() const { return adj.size(); }
inline int edge_size() const { return edges.size(); }
inline edge_type &edge(int i) { return edges[i]; }
inline edge_type edge(int i) const { return edges[i]; }
inline vector<edge_type> all_edges() const { return edges; }
template <typename S = V,
typename enable_if<!is_void<S>::value>::type * = nullptr>
inline S &vertex(int i) {
return vertices[i];
}
template <typename S = V,
typename enable_if<!is_void<S>::value>::type * = nullptr>
inline V vertex(int i) const {
return vertices[i];
}
template <typename S = V,
typename enable_if<is_void<S>::value>::type * = nullptr>
inline void add_vertex() {
adj.emplace_back();
}
template <typename S = V,
typename enable_if<!is_void<S>::value>::type * = nullptr>
inline S &add_vertex() {
adj.emplace_back();
return vertices.emplace_back().data;
}
template <typename S = E,
typename enable_if<is_void<S>::value>::type * = nullptr>
inline void add_edge_(int u, int v) {
adj[u].push_back(edges.size());
edges.push_back({u, v});
}
template <typename S = E,
typename enable_if<!is_void<S>::value>::type * = nullptr>
inline S &add_edge_(int u, int v) {
adj[u].push_back(edges.size());
edges.push_back({u, v});
return edges.back().data;
}
void add_2edge(int u, int v) {
add_edge_(u, v);
add_edge_(v, u);
}
template <typename S = E,
typename enable_if<!is_void<S>::value>::type * = nullptr>
inline void add_2edge(int u, int v, const S &data) {
add_edge_(u, v) = data;
add_edge_(v, u) = data;
}
template <typename S = E,
typename enable_if<is_void<S>::value && Directed>::type * = nullptr>
inline void add_edge(int u, int v) {
adj[u].push_back(edges.size());
edges.push_back({u, v});
}
template <typename S = E,
typename enable_if<!is_void<S>::value && Directed>::type * = nullptr>
inline S &add_edge(int u, int v) {
adj[u].push_back(edges.size());
edges.push_back({u, v});
return edges.back().data;
}
};
template<typename V = void, typename E = void>
using Graph = GraphImpl<V, E, false>;
template<typename V = void, typename E = void>
using DirectedGraph = GraphImpl<V, E, true>;
template <typename V = void, typename E = void>
struct RootedForest : public DirectedGraph<V, E> {
typedef RootedForest<V, E> self_type;
using typename DirectedGraph<V, E>::adj_list;
using typename DirectedGraph<V, E>::edge_type;
using DirectedGraph<V, E>::DirectedGraph;
using DirectedGraph<V, E>::adj;
using DirectedGraph<V, E>::edge;
vector<int> p, pe;
void build_parents() {
if ((int)p.size() == this->size())
return;
int n = this->size();
stack<int> st;
vector<bool> vis(n);
p.assign(n, -1), pe.assign(n, -1);
for (int i = 0; i < n; i++) {
if (!vis[i]) {
st.push(i);
vis[i] = true;
while (!st.empty()) {
int u = st.top();
st.pop();
for (int k : adj[u]) {
int v = edge(k).to;
vis[v] = true;
st.push(v), pe[v] = k, p[v] = u;
}
}
}
}
}
inline int parent(int i) const {
const_cast<self_type *>(this)->build_parents();
return p[i];
}
inline bool is_root(int i) const { return parent(i) != -1; }
inline edge_type &parent_edge(int i) {
build_parents();
return edge(pe[i]);
}
inline edge_type &parent_edge(int i) const {
const_cast<self_type *>(this)->build_parents();
return edge(pe[i]);
}
vector<int> roots() const {
vector<int> res;
const_cast<self_type *>(this)->build_parents();
int n = this->size();
for (int i = 0; i < n; i++)
if (p[i] == -1)
res.push_back(i);
return res;
}
};
template <typename V = void, typename E = void>
struct RootedTree : public RootedForest<V, E> {
using typename RootedForest<V, E>::adj_list;
int root;
RootedTree(int n, int root) : RootedForest<V, E>(n) {
assert(n > 0);
assert(root < n);
this->root = root;
}
RootedTree(const adj_list &adj, int root) : RootedForest<V, E>(adj) {
assert(adj.size() > 0);
assert(root < adj.size());
this->root = root;
}
};
namespace builders {
namespace {
template <typename F, typename G>
void dfs_rooted_forest(F &forest, const G &graph, int u, vector<bool> &vis) {
vis[u] = true;
for (const auto &ed : graph.n_edges(u)) {
int v = ed.to;
if (!vis[v]) {
forest.add_edge(u, v);
dfs_rooted_forest(forest, graph, v, vis);
}
}
}
} // namespace
template <typename A, typename B>
RootedForest<A, B> make_rooted_forest(const Graph<A, B> &graph,
const vector<int> &roots) {
RootedForest<A, B> res(graph.size());
vector<bool> vis(graph.size());
for (int i : roots)
if (!vis[i])
dfs_rooted_forest(res, graph, i, vis);
for (int i = 0; i < graph.size(); i++)
if (!vis[i])
dfs_rooted_forest(res, graph, i, vis);
return res;
}
} // namespace builders
} // namespace graph
} // namespace lib
#line 1 "utils/LazyArray.cpp"
#line 4 "utils/LazyArray.cpp"
namespace lib {
using namespace std;
template<typename T>
struct LazyArray {
vector<T> v;
vector<int> lz;
T lz_v;
int tempo = 1;
LazyArray() {}
LazyArray(int n, T lz_v) : v(n), lz(n), lz_v(lz_v) {}
int size() const { return v.size(); }
void fill(T vv) { lz_v = vv, tempo++; }
void clear() {
fill(T());
}
T get(int i) const {
return tempo == lz[i] ? v[i] : lz_v;
}
T operator[](int i) const {
return get(i);
}
T& operator[](int i) {
if(lz[i] != tempo) {
lz[i] = tempo;
v[i] = lz_v;
}
return v[i];
}
};
} // namespace lib
#line 6 "graphs/BlockCut.cpp"
namespace lib {
using namespace std;
namespace graph {
template<typename V, typename E>
struct BlockCut {
int n, m;
Graph<V, E> g;
int tempo = 0;
vector<int> vis, low, seen;
vector<int> st;
LazyArray<char> seen_v;
Graph<V, E> g2;
int n2 = 0;
BlockCut(const Graph<V, E>& g) : g(g) {
n = g.size();
m = g.edge_size();
vis = low = vector<int>(n);
seen = vector<int>(m);
st.reserve(m);
seen_v = LazyArray<char>(n, 0);
g2 = Graph<V, E>(n);
for(int i = 0; i < n; i++) {
if(!vis[i]) {
tarjan(i, -1);
if (g.degree(i) == 0) {
// Vertex is isolated, process separately.
g2.add_vertex();
g2.add_2edge(n + n2, i);
n2++;
}
}
}
}
Graph<V, E> graph() const { return g2; }
int n_components() const { return n2; }
vector<int> component(int i) const {
vector<int> res;
for(const auto& v : g2.n_edges(n + i))
if (v.to < n)
res.push_back(v.to);
return res;
}
vector<int> get_vertices_(const vector<int>& e) {
seen_v.clear();
vector<int> comp;
for(int kk : e) {
auto ed = g.edge(kk);
if(!seen_v.get(ed.from)) comp.push_back(ed.from), seen_v[ed.from] = true;
if(!seen_v.get(ed.to)) comp.push_back(ed.to), seen_v[ed.to] = true;
}
return comp;
}
void process_component_(int k) {
vector<int> e;
int cur;
do {
cur = st.back(); st.pop_back();
e.push_back(cur);
} while(cur != k);
auto comp = get_vertices_(e);
g2.add_vertex();
for(int w : comp) {
g2.add_2edge(n + n2, w);
}
n2++;
}
void tarjan(int u, int p) {
vis[u] = low[u] = ++tempo;
auto nei = g.n_edges(u);
for(int i = 0; i < nei.size(); i++) {
int k = nei.index(i);
int v = g.edge(k).to;
if(!seen[k]) {
seen[k] = seen[k^1] = 1;
st.push_back(k);
}
if(!vis[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= vis[u]) {
process_component_(k);
}
} else {
low[u] = min(low[u], vis[v]);
}
}
}
};
template<typename V, typename E>
BlockCut<V, E> make_block_cut(const Graph<V, E>& g) {
return BlockCut<V, E>(g);
}
} // namespace graph
} // namespace lib
#line 2 "Template.cpp"
#define int long long
using namespace std;
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define ms(v, x) memset((v), (x), sizeof(v))
#define all(v) (v).begin(), (v).end()
#define ff first
#define ss second
#define iopt ios::sync_with_stdio(false); cin.tie(0)
#define untie(p, a, b) decltype(p.first) a = p.first, decltype(p.second) b = p.second
#define TESTCASE(tn) cout << "Case #" << tn << ": "
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int floor2(int x, int y);
int ceil2(int x, int y) {
if(y < 0) return ceil2(-x, -y);
return x < 0 ? -floor2(-x, y) : (x + y - 1) / y;
}
int floor2(int x, int y) {
if(y < 0) return floor2(-x, -y);
return x < 0 ? -ceil2(-x, y) : x / y;
}
typedef pair<int, int> ii;
typedef long double LD;
typedef vector<int> vi;
#define TC_MAIN int32_t main() { iopt; int T; cin >> T; for(int i = 1; i <= T; i++) solve(i); }
#line 5 "tests/yosupo/biconnected-components.test.cpp"
using namespace lib;
int32_t main() {
iopt;
int n, m; cin >> n >> m;
graph::Graph<int> g(n);
for(int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
g.add_2edge(a, b);
}
auto bct = graph::make_block_cut(g);
cout << bct.n_components() << endl;
for(int i = 0; i < bct.n_components(); i++) {
const auto comp = bct.component(i);
cout << comp.size() << " ";
for(const auto v : comp) cout << v << " ";
cout << endl;
}
}