This documentation is automatically generated by online-judge-tools/verification-helper
#include "src/graph/LowLink.hpp"Block Cut Tree
Lowlink による橋と関節点の列挙,その上で二重辺連結成分分解や二重頂点連結成分分解の構成を行う.
橋と関節点を dfs-tree を利用して頂点数及び辺数に対して線形時間で行うのが Lowlink である. 具体的には,dfs-tree での頂点 $v$ の訪問時刻を $ord_v$,$v$ から後退辺を高々一度だけ用いて到達できる頂点集合における $ord$ の最小値を $low_v$ と定義すると,各辺の両端点におけるこれらの値のみから頂点が関節点であるかや辺が橋であるかを判定することが可能である.
どの辺を取り除いても連結であるような連結グラフを二重辺連結成分という. 一般のグラフにおいて,橋でないような辺のみを含むグラフの各連結成分は二重辺連結成分をなす. 元のグラフにおいて各二重辺連結成分を縮約してできるグラフは木構造をなす.
どの点とそれに接続する辺を取り除いても連結であるような連結グラフを二重頂点連結成分という. これも二重辺連結成分に比べると少し複雑だが,関節点で区切ることで二重頂点連結成分をなす(関節点を倍化するとわかりやすいかもしれない).
二重頂点連結成分を縮約して一つの点とみなし,さらに関節点もそれとは独立した点と考えると,これらは木構造をなす. これが Block Cut Tree である.
| メンバ関数 | 効果 | 時間計算量 |
|---|---|---|
LowLink(n) |
$n$ 頂点 $0$ 辺のグラフとして初期化する. | $O(n)$ |
add_edge(u, v) |
頂点 $u$ と頂点 $v$ を結ぶ辺を追加する. | $O(1)$ |
build() |
各種構成を行う. | $O(n + m)$ |
#pragma once
#include <cassert>
#include <utility>
#include <vector>
struct LowLink {
int n, m = 0, t = 0, b = 0;
std::vector<std::vector<int>> G;
std::vector<std::pair<int, int>> es;
std::vector<int> ord, low, tecc, bcc, tmp;
std::vector<bool> is_articulation, is_bridge;
LowLink(int n) : n(n), G(n), ord(n, -1), low(n), tecc(n, -1), is_articulation(n, false) {}
void add_edge(int u, int v) {
assert(0 <= u and u < n);
assert(0 <= v and v < n);
G[u].emplace_back(m);
G[v].emplace_back(m);
es.emplace_back(u, v);
is_bridge.emplace_back(false);
bcc.emplace_back();
m++;
}
void build() {
for (int i = 0; i < n; i++) {
if (ord[i] != -1) continue;
dfs1(i, 0, -1);
dfs2(i, -1);
}
}
std::pair<int, int> operator[](int k) const { return es[k]; }
private:
void dfs1(int v, int k, int pre) {
ord[v] = k++, low[v] = ord[v];
int cnt = 0;
for (int& e : G[v]) {
if (e == pre) continue;
int u = es[e].first ^ es[e].second ^ v;
if (ord[u] == -1) {
cnt++;
dfs1(u, k, e);
low[v] = std::min(low[v], low[u]);
if (pre != -1 and ord[v] <= low[u]) is_articulation[v] = true;
if (ord[v] < low[u]) is_bridge[e] = true;
} else
low[v] = std::min(low[v], ord[u]);
}
if (pre == -1 and cnt > 1) is_articulation[v] = true;
}
void dfs2(int v, int pre) {
if (pre == -1) tecc[v] = t++;
for (int& e : G[v]) {
if (e == pre) continue;
int u = es[e].first ^ es[e].second ^ v;
if (tecc[u] == -1 or ord[u] < ord[v]) tmp.emplace_back(e);
if (tecc[u] >= 0) continue;
if (ord[v] >= low[u])
tecc[u] = tecc[v];
else
tecc[u] = t++;
dfs2(u, e);
if (ord[v] <= low[u]) {
while (true) {
int ne = tmp.back();
tmp.pop_back();
bcc[ne] = b;
if (ne == e) break;
}
b++;
}
}
}
};#line 2 "src/graph/LowLink.hpp"
#include <cassert>
#include <utility>
#include <vector>
struct LowLink {
int n, m = 0, t = 0, b = 0;
std::vector<std::vector<int>> G;
std::vector<std::pair<int, int>> es;
std::vector<int> ord, low, tecc, bcc, tmp;
std::vector<bool> is_articulation, is_bridge;
LowLink(int n) : n(n), G(n), ord(n, -1), low(n), tecc(n, -1), is_articulation(n, false) {}
void add_edge(int u, int v) {
assert(0 <= u and u < n);
assert(0 <= v and v < n);
G[u].emplace_back(m);
G[v].emplace_back(m);
es.emplace_back(u, v);
is_bridge.emplace_back(false);
bcc.emplace_back();
m++;
}
void build() {
for (int i = 0; i < n; i++) {
if (ord[i] != -1) continue;
dfs1(i, 0, -1);
dfs2(i, -1);
}
}
std::pair<int, int> operator[](int k) const { return es[k]; }
private:
void dfs1(int v, int k, int pre) {
ord[v] = k++, low[v] = ord[v];
int cnt = 0;
for (int& e : G[v]) {
if (e == pre) continue;
int u = es[e].first ^ es[e].second ^ v;
if (ord[u] == -1) {
cnt++;
dfs1(u, k, e);
low[v] = std::min(low[v], low[u]);
if (pre != -1 and ord[v] <= low[u]) is_articulation[v] = true;
if (ord[v] < low[u]) is_bridge[e] = true;
} else
low[v] = std::min(low[v], ord[u]);
}
if (pre == -1 and cnt > 1) is_articulation[v] = true;
}
void dfs2(int v, int pre) {
if (pre == -1) tecc[v] = t++;
for (int& e : G[v]) {
if (e == pre) continue;
int u = es[e].first ^ es[e].second ^ v;
if (tecc[u] == -1 or ord[u] < ord[v]) tmp.emplace_back(e);
if (tecc[u] >= 0) continue;
if (ord[v] >= low[u])
tecc[u] = tecc[v];
else
tecc[u] = t++;
dfs2(u, e);
if (ord[v] <= low[u]) {
while (true) {
int ne = tmp.back();
tmp.pop_back();
bcc[ne] = b;
if (ne == e) break;
}
b++;
}
}
}
};