This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "tools/lowlink.hpp"
Given an undirected graph, it creates a data structure that allows enumeration of bridges and articulation points in linear time. The graph may contain self-loops and multiple edges, and need not be connected.
lowlink graph(int n);
It creates an undirected graph with $n$ vertices and $0$ edges.
int graph.size();
It returns $n$.
int graph.add_edge(int u, int v);
It adds an undirected edge connecting vertex $u$ and vertex $v$ to the graph, and returns the number of edges that existed before the undirected edge was added.
graph.build()
has not been called ever.struct edge {
int from;
int to;
};
const edge& graph.get_edge(int k);
It returns information about the $k$-th edge in $0$-indexed.
The information means that the $k$-th edge added to this graph is the undirected edge connecting vertex from
and vertex to
.
Of course, as this is an undirected graph, the from
and to
orientations are meaningless.
In an undirected graph such as this graph, the vertex numbers are always sorted so that from
$\leq$ to
.
const std::vector<edge>& graph.edges();
It returns all the edges in the graph.
The edges are ordered in the same order as added by add_edge
.
struct edges_iterable {
struct iterator {
const edge& operator*();
iterator& operator++();
iterator operator++(int):
friend bool operator==(iterator lhs, iterator rhs);
friend bool operator!=(iterator lhs, iterator rhs);
};
iterator begin();
iterator end();
};
edges_iterable graph.edges(int v);
It returns an iterator that enumerates the edges adjacent to vertex $v$. The enumeration order is undefined, except that each element appears exactly once.
struct neighbors_iterable {
struct iterator {
int operator*();
iterator& operator++();
iterator operator++(int):
friend bool operator==(iterator lhs, iterator rhs);
friend bool operator!=(iterator lhs, iterator rhs);
};
iterator begin();
iterator end();
};
neighbors_iterable graph.neighbors(int v);
It returns an iterator that enumerates the vertices adjacent to vertex $v$. The enumeration order is undefined. If the graph contains multiple edges, a vertex may appear more than once. Also, if the graph contains self-loops, vertex $v$ itself may appear in the enumeration.
void graph.build();
It creates a data structure that allows bridges and articulation points to be enumerated in linear time. The key elements are values called $\mathrm{ord}(v)$ and $\mathrm{low}(v)$ assigned to each vertex $v$, which are defined as follows.
We first repeat the process of creating a spanning tree for each connected component of the graph by a depth-first search, choosing the roots as appropriate. We call this spanning tree a DFS tree, and the edges belonging to the DFS tree are called tree edges. We regard a tree edge as a directed edge from the root side to the leaf side.
We also refer to edges that do not belong to the DFS tree as back edges. Back edges are known to have both endpoints always in an ancestor-descendant relationship. We regard a back edge as a directed edge from the leaf side to the root side.
We define $\mathrm{ord}(v)$ and $\mathrm{low}(v)$ as values determined for each vertex $v$ of the spanning tree. The definition of $\mathrm{ord}(v)$ is the pre-ordered vertex number of the DFS tree. The $\mathrm{ord}(r)$ of root $r$ is $0$. The definition of $\mathrm{low}(v)$ is $\displaystyle \min_{s \in S}\left(\mathrm{ord}\left(s\right)\right)$, where $S$ is the set of vertices reachable from vertex $v$ using zero or more tree edges and one or less back edges.
Note that there are as many vertices $v$ such that $\mathrm{ord}(v) = 0$ as there are connected components.
graph.build()
has not been called ever.int graph.vparent(int v);
It returns $u$ such that the parent of vertex $v$ in the DFS tree is vertex $u$.
graph.build()
has been called ever.const edge& graph.eparent(int v);
It returns the tree edge towards vertex $v$.
graph.build()
has been called ever.struct vchildren_iterable {
struct iterator {
int operator*();
iterator& operator++();
iterator operator++(int):
friend bool operator==(iterator lhs, iterator rhs);
friend bool operator!=(iterator lhs, iterator rhs);
};
iterator begin();
iterator end();
};
vchildren_iterable graph.vchildren(int v);
It returns $u$ such that the parent of vertex $u$ in the DFS tree is vertex $v$.
graph.build()
has been called ever.struct echildren_iterable {
struct iterator {
const edge& operator*();
iterator& operator++();
iterator operator++(int):
friend bool operator==(iterator lhs, iterator rhs);
friend bool operator!=(iterator lhs, iterator rhs);
};
iterator begin();
iterator end();
};
echildren_iterable graph.echildren(int v);
It returns the tree edges outward from vertex $v$.
graph.build()
has been called ever.int graph.ord(int v);
It returns $\mathrm{ord}(v)$.
graph.build()
has been called ever.int graph.low(int v);
It returns $\mathrm{low}(v)$.
graph.build()
has been called ever.int graph.ncc();
It returns the number of connected components of the graph.
graph.build()
has been called ever.int graph.ncc_without_vertex(int v);
It returns the number of connected components of the graph without vertex $v$.
graph.build()
has been called ever.bool graph.is_articulation_point(int v);
It returns whether vertex $v$ is an articulation point or not.
graph.build()
has been called ever.bool graph.is_bridge(int k);
It returns whether the $k$-th edge is a bridge or not.
graph.build()
has been called ever.std::vector<std::vector<int>> graph.biconnected_components();
It divides the graph into biconnected components and returns the list of them.
More precisely, it returns the list of the “list of the vertices in a biconnected component”. Both of the orders of the biconnected components and the vertices are undefined.
graph.build()
has been called ever.#ifndef TOOLS_LOWLINK_HPP
#define TOOLS_LOWLINK_HPP
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <stack>
#include <tuple>
#include <utility>
#include <vector>
#include "tools/chmin.hpp"
#include "tools/fix.hpp"
#include "tools/less_by.hpp"
namespace tools {
class lowlink {
public:
struct edge {
int from;
int to;
};
private:
::std::vector<edge> m_edges;
::std::vector<::std::vector<int>> m_graph;
bool m_built;
::std::vector<int> m_from;
::std::vector<int> m_ord;
::std::vector<int> m_low;
int m_ncc;
::std::vector<int> m_ncc_without_vertex;
public:
class neighbors_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = int;
using reference = const int&;
using pointer = const int*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
}
value_type operator*() const {
const auto& edge = this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
return edge.from ^ edge.to ^ this->m_v;
}
iterator& operator++() {
++this->m_i;
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
neighbors_iterable() = default;
neighbors_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class edges_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = edge;
using reference = const edge&;
using pointer = const edge*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
}
reference operator*() const {
return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
}
iterator& operator++() {
++this->m_i;
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
edges_iterable() = default;
edges_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class vchildren_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = int;
using reference = const int&;
using pointer = const int*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
const auto& eids = this->m_parent->m_graph[this->m_v];
for (; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
}
value_type operator*() const {
const auto& edge = this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
return edge.from ^ edge.to ^ this->m_v;
}
iterator& operator++() {
const auto& eids = this->m_parent->m_graph[this->m_v];
assert(this->m_i < eids.size());
for (++this->m_i; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
vchildren_iterable() = default;
vchildren_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class echildren_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = edge;
using reference = const edge&;
using pointer = const edge*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
const auto& eids = this->m_parent->m_graph[this->m_v];
for (; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
}
reference operator*() const {
return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
}
iterator& operator++() {
const auto& eids = this->m_parent->m_graph[this->m_v];
assert(this->m_i < eids.size());
for (++this->m_i; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
echildren_iterable() = default;
echildren_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
lowlink() = default;
explicit lowlink(const int n) : m_graph(n), m_built(false) {
}
int size() const {
return this->m_graph.size();
}
int add_edge(int u, int v) {
assert(!this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
::std::tie(u, v) = ::std::minmax({u, v});
this->m_edges.push_back(edge{u, v});
this->m_graph[u].push_back(this->m_edges.size() - 1);
this->m_graph[v].push_back(this->m_edges.size() - 1);
return this->m_edges.size() - 1;
}
const edge& get_edge(const int k) const {
assert(0 <= k && k < this->m_edges.size());
return this->m_edges[k];
}
const ::std::vector<edge>& edges() const {
return this->m_edges;
}
neighbors_iterable neighbors(const int v) const {
assert(0 <= v && v < this->size());
return neighbors_iterable(this, v);
}
edges_iterable edges(const int v) const {
assert(0 <= v && v < this->size());
return edges_iterable(this, v);
}
void build() {
assert(!this->m_built);
this->m_built = true;
const auto N_A = -1;
this->m_from.assign(this->size(), N_A);
this->m_ord.assign(this->size(), N_A);
this->m_low.assign(this->size(), N_A);
this->m_ncc = 0;
for (int r = 0; r < this->size(); ++r) {
if (this->m_ord[r] != N_A) continue;
++this->m_ncc;
int next_ord = 0;
::std::stack<::std::pair<int, int>> stack;
stack.emplace(r, N_A);
stack.emplace(r, N_A - 1);
while (!stack.empty()) {
const auto [v, from] = stack.top();
stack.pop();
if (from != N_A) {
if (this->m_ord[v] != N_A) continue;
this->m_from[v] = from;
this->m_ord[v] = next_ord++;
for (const auto eid : this->m_graph[v]) {
const auto& edge = this->m_edges[eid];
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[u] != N_A) continue;
stack.emplace(u, N_A);
stack.emplace(u, eid);
}
} else {
if (this->m_low[v] != N_A) continue;
this->m_low[v] = this->m_ord[v];
for (const auto eid : this->m_graph[v]) {
const auto& edge = this->m_edges[eid];
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[u] < this->m_ord[v] && eid != this->m_from[v]) {
::tools::chmin(this->m_low[v], this->m_ord[u]);
} else if (this->m_ord[u] > this->m_ord[v] && eid == this->m_from[u]) {
::tools::chmin(this->m_low[v], this->m_low[u]);
}
}
}
}
this->m_from[r] = N_A;
}
this->m_ncc_without_vertex.assign(this->size(), this->m_ncc);
for (int v = 0; v < this->size(); ++v) {
if (this->m_ord[v] == 0) {
this->m_ncc_without_vertex[v] += ::std::distance(this->echildren(v).begin(), this->echildren(v).end());
--this->m_ncc_without_vertex[v];
} else {
for (const auto& edge : this->echildren(v)) {
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[v] <= this->m_low[u]) {
++this->m_ncc_without_vertex[v];
}
}
}
}
}
int vparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_ord[v] > 0);
const auto& edge = this->m_edges[this->m_from[v]];
return edge.from ^ edge.to ^ v;
}
const edge& eparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_ord[v] > 0);
return this->m_edges[this->m_from[v]];
}
vchildren_iterable vchildren(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return vchildren_iterable(this, v);
}
echildren_iterable echildren(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return echildren_iterable(this, v);
}
int ord(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ord[v];
}
int low(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_low[v];
}
int ncc() const {
assert(this->m_built);
return this->m_ncc;
}
int ncc_without_vertex(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ncc_without_vertex[v];
}
bool is_articulation_point(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ncc_without_vertex[v] > this->m_ncc;
}
bool is_bridge(const int k) const {
assert(this->m_built);
assert(0 <= k && k < this->m_edges.size());
const auto [u, v] = ::std::minmax({this->m_edges[k].from, this->m_edges[k].to}, ::tools::less_by([&](const auto w) { return this->m_ord[w]; }));
return this->m_ord[u] < this->m_low[v];
}
::std::vector<::std::vector<int>> biconnected_components() const {
assert(this->m_built);
::std::vector<::std::vector<int>> groups;
for (int r = 0; r < this->size(); ++r) {
if (this->ord(r) == 0) {
if (this->m_ncc_without_vertex[r] < this->m_ncc) {
groups.emplace_back(::std::initializer_list<int>{r});
} else {
::tools::fix([&](auto&& dfs, const auto g, const auto v) -> void {
for (const auto u : this->vchildren(v)) {
if (this->ord(v) <= this->low(u)) {
groups.emplace_back(::std::initializer_list<int>{v, u});
dfs(groups.size() - 1, u);
} else {
groups[g].push_back(u);
dfs(g, u);
}
}
})(-1, r);
}
}
}
return groups;
}
};
}
#endif
#line 1 "tools/lowlink.hpp"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <stack>
#include <tuple>
#include <utility>
#include <vector>
#line 1 "tools/chmin.hpp"
#include <type_traits>
#line 6 "tools/chmin.hpp"
namespace tools {
template <typename M, typename N>
bool chmin(M& lhs, const N& rhs) {
bool updated;
if constexpr (::std::is_integral_v<M> && ::std::is_integral_v<N>) {
updated = ::std::cmp_less(rhs, lhs);
} else {
updated = rhs < lhs;
}
if (updated) lhs = rhs;
return updated;
}
}
#line 1 "tools/fix.hpp"
#line 6 "tools/fix.hpp"
namespace tools {
template <typename F>
struct fix : F {
template <typename G>
fix(G&& g) : F({::std::forward<G>(g)}) {
}
template <typename... Args>
decltype(auto) operator()(Args&&... args) const {
return F::operator()(*this, ::std::forward<Args>(args)...);
}
};
template <typename F>
fix(F&&) -> fix<::std::decay_t<F>>;
}
#line 1 "tools/less_by.hpp"
namespace tools {
template <class F>
class less_by {
private:
F selector;
public:
less_by(const F& selector) : selector(selector) {
}
template <class T>
bool operator()(const T& x, const T& y) const {
return selector(x) < selector(y);
}
};
}
#line 17 "tools/lowlink.hpp"
namespace tools {
class lowlink {
public:
struct edge {
int from;
int to;
};
private:
::std::vector<edge> m_edges;
::std::vector<::std::vector<int>> m_graph;
bool m_built;
::std::vector<int> m_from;
::std::vector<int> m_ord;
::std::vector<int> m_low;
int m_ncc;
::std::vector<int> m_ncc_without_vertex;
public:
class neighbors_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = int;
using reference = const int&;
using pointer = const int*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
}
value_type operator*() const {
const auto& edge = this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
return edge.from ^ edge.to ^ this->m_v;
}
iterator& operator++() {
++this->m_i;
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
neighbors_iterable() = default;
neighbors_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class edges_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = edge;
using reference = const edge&;
using pointer = const edge*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
}
reference operator*() const {
return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
}
iterator& operator++() {
++this->m_i;
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
edges_iterable() = default;
edges_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class vchildren_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = int;
using reference = const int&;
using pointer = const int*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
const auto& eids = this->m_parent->m_graph[this->m_v];
for (; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
}
value_type operator*() const {
const auto& edge = this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
return edge.from ^ edge.to ^ this->m_v;
}
iterator& operator++() {
const auto& eids = this->m_parent->m_graph[this->m_v];
assert(this->m_i < eids.size());
for (++this->m_i; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
vchildren_iterable() = default;
vchildren_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
class echildren_iterable {
private:
::tools::lowlink const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::lowlink const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = edge;
using reference = const edge&;
using pointer = const edge*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::lowlink const * const parent, const int v, const int i) : m_parent(parent), m_v(v), m_i(i) {
const auto& eids = this->m_parent->m_graph[this->m_v];
for (; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
}
reference operator*() const {
return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]];
}
iterator& operator++() {
const auto& eids = this->m_parent->m_graph[this->m_v];
assert(this->m_i < eids.size());
for (++this->m_i; this->m_i < eids.size() && [&]() {
const auto eid = eids[this->m_i];
const auto& edge = this->m_parent->m_edges[eid];
return this->m_parent->m_from[edge.from ^ edge.to ^ this->m_v] != eid;
}(); ++this->m_i);
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
assert(lhs.m_parent == rhs.m_parent);
assert(lhs.m_v == rhs.m_v);
return lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
echildren_iterable() = default;
echildren_iterable(::tools::lowlink const * const parent, const int v) : m_parent(parent), m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
lowlink() = default;
explicit lowlink(const int n) : m_graph(n), m_built(false) {
}
int size() const {
return this->m_graph.size();
}
int add_edge(int u, int v) {
assert(!this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
::std::tie(u, v) = ::std::minmax({u, v});
this->m_edges.push_back(edge{u, v});
this->m_graph[u].push_back(this->m_edges.size() - 1);
this->m_graph[v].push_back(this->m_edges.size() - 1);
return this->m_edges.size() - 1;
}
const edge& get_edge(const int k) const {
assert(0 <= k && k < this->m_edges.size());
return this->m_edges[k];
}
const ::std::vector<edge>& edges() const {
return this->m_edges;
}
neighbors_iterable neighbors(const int v) const {
assert(0 <= v && v < this->size());
return neighbors_iterable(this, v);
}
edges_iterable edges(const int v) const {
assert(0 <= v && v < this->size());
return edges_iterable(this, v);
}
void build() {
assert(!this->m_built);
this->m_built = true;
const auto N_A = -1;
this->m_from.assign(this->size(), N_A);
this->m_ord.assign(this->size(), N_A);
this->m_low.assign(this->size(), N_A);
this->m_ncc = 0;
for (int r = 0; r < this->size(); ++r) {
if (this->m_ord[r] != N_A) continue;
++this->m_ncc;
int next_ord = 0;
::std::stack<::std::pair<int, int>> stack;
stack.emplace(r, N_A);
stack.emplace(r, N_A - 1);
while (!stack.empty()) {
const auto [v, from] = stack.top();
stack.pop();
if (from != N_A) {
if (this->m_ord[v] != N_A) continue;
this->m_from[v] = from;
this->m_ord[v] = next_ord++;
for (const auto eid : this->m_graph[v]) {
const auto& edge = this->m_edges[eid];
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[u] != N_A) continue;
stack.emplace(u, N_A);
stack.emplace(u, eid);
}
} else {
if (this->m_low[v] != N_A) continue;
this->m_low[v] = this->m_ord[v];
for (const auto eid : this->m_graph[v]) {
const auto& edge = this->m_edges[eid];
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[u] < this->m_ord[v] && eid != this->m_from[v]) {
::tools::chmin(this->m_low[v], this->m_ord[u]);
} else if (this->m_ord[u] > this->m_ord[v] && eid == this->m_from[u]) {
::tools::chmin(this->m_low[v], this->m_low[u]);
}
}
}
}
this->m_from[r] = N_A;
}
this->m_ncc_without_vertex.assign(this->size(), this->m_ncc);
for (int v = 0; v < this->size(); ++v) {
if (this->m_ord[v] == 0) {
this->m_ncc_without_vertex[v] += ::std::distance(this->echildren(v).begin(), this->echildren(v).end());
--this->m_ncc_without_vertex[v];
} else {
for (const auto& edge : this->echildren(v)) {
const auto u = edge.from ^ edge.to ^ v;
if (this->m_ord[v] <= this->m_low[u]) {
++this->m_ncc_without_vertex[v];
}
}
}
}
}
int vparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_ord[v] > 0);
const auto& edge = this->m_edges[this->m_from[v]];
return edge.from ^ edge.to ^ v;
}
const edge& eparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_ord[v] > 0);
return this->m_edges[this->m_from[v]];
}
vchildren_iterable vchildren(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return vchildren_iterable(this, v);
}
echildren_iterable echildren(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return echildren_iterable(this, v);
}
int ord(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ord[v];
}
int low(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_low[v];
}
int ncc() const {
assert(this->m_built);
return this->m_ncc;
}
int ncc_without_vertex(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ncc_without_vertex[v];
}
bool is_articulation_point(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_ncc_without_vertex[v] > this->m_ncc;
}
bool is_bridge(const int k) const {
assert(this->m_built);
assert(0 <= k && k < this->m_edges.size());
const auto [u, v] = ::std::minmax({this->m_edges[k].from, this->m_edges[k].to}, ::tools::less_by([&](const auto w) { return this->m_ord[w]; }));
return this->m_ord[u] < this->m_low[v];
}
::std::vector<::std::vector<int>> biconnected_components() const {
assert(this->m_built);
::std::vector<::std::vector<int>> groups;
for (int r = 0; r < this->size(); ++r) {
if (this->ord(r) == 0) {
if (this->m_ncc_without_vertex[r] < this->m_ncc) {
groups.emplace_back(::std::initializer_list<int>{r});
} else {
::tools::fix([&](auto&& dfs, const auto g, const auto v) -> void {
for (const auto u : this->vchildren(v)) {
if (this->ord(v) <= this->low(u)) {
groups.emplace_back(::std::initializer_list<int>{v, u});
dfs(groups.size() - 1, u);
} else {
groups[g].push_back(u);
dfs(g, u);
}
}
})(-1, r);
}
}
}
return groups;
}
};
}