Skip to content

Commit 726b96a

Browse files
committed
add 2cc, bcc
1 parent 083f3f8 commit 726b96a

File tree

5 files changed

+203
-3
lines changed

5 files changed

+203
-3
lines changed

cp-algo/graph/2cc.hpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef CP_ALGO_GRAPH_2CC_HPP
2+
#define CP_ALGO_GRAPH_2CC_HPP
3+
#include "base.hpp"
4+
#include "../structures/csr.hpp"
5+
#include <algorithm>
6+
7+
namespace cp_algo::graph {
8+
template<undirected_graph_type graph>
9+
structures::csr<node_index> two_edge_connected_components(graph const& g) {
10+
structures::csr<node_index> components;
11+
components.reserve_data(g.n());
12+
enum node_state { unvisited, visited, blocked };
13+
std::vector<node_state> state(g.n());
14+
15+
auto collect = [&](this auto &&collect, node_index v) -> void {
16+
state[v] = blocked;
17+
components.push(v);
18+
for (auto e : g.outgoing(v)) {
19+
node_index u = g.edge(e).to;
20+
if (state[u] != blocked) collect(u);
21+
}
22+
};
23+
24+
big_vector<int> tin(g.n()), low(g.n());
25+
int timer = 0;
26+
auto dfs = [&](this auto &&dfs, node_index v, edge_index ep = -1) -> void {
27+
tin[v] = low[v] = timer++;
28+
state[v] = blocked;
29+
for (auto e: g.outgoing(v)) {
30+
if (ep == graph::opposite_idx(e)) {
31+
continue;
32+
}
33+
node_index u = g.edge(e).to;
34+
if (state[u] == unvisited) {
35+
dfs(u, e);
36+
low[v] = std::min(low[v], low[u]);
37+
} else {
38+
low[v] = std::min(low[v], tin[u]);
39+
}
40+
}
41+
if (low[v] == tin[v]) {
42+
components.new_row();
43+
collect(v);
44+
} else {
45+
state[v] = visited;
46+
}
47+
};
48+
49+
for (auto v : g.nodes()) {
50+
if (state[v] == unvisited) {
51+
if (std::ranges::empty(g.outgoing(v))) {
52+
components.new_row();
53+
components.push(v);
54+
} else {
55+
dfs(v);
56+
}
57+
}
58+
}
59+
return components;
60+
}
61+
}
62+
63+
#endif // CP_ALGO_GRAPH_2CC_HPP

cp-algo/graph/bcc.hpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef CP_ALGO_GRAPH_BCC_HPP
2+
#define CP_ALGO_GRAPH_BCC_HPP
3+
#include "base.hpp"
4+
#include "../structures/csr.hpp"
5+
#include <algorithm>
6+
7+
namespace cp_algo::graph {
8+
template<undirected_graph_type graph>
9+
structures::csr<node_index> biconnected_components(graph const& g) {
10+
structures::csr<node_index> components;
11+
components.reserve_data(g.n());
12+
enum node_state { unvisited, visited, blocked };
13+
std::vector<node_state> state(g.n());
14+
15+
auto collect = [&](this auto &&collect, node_index v) -> void {
16+
state[v] = blocked;
17+
components.push(v);
18+
for (auto e : g.outgoing(v)) {
19+
node_index u = g.edge(e).to;
20+
if (state[u] != blocked) collect(u);
21+
}
22+
};
23+
24+
big_vector<int> tin(g.n()), low(g.n());
25+
int timer = 0;
26+
auto dfs = [&](this auto &&dfs, node_index v, edge_index ep = -1) -> void {
27+
tin[v] = low[v] = timer++;
28+
state[v] = blocked;
29+
for (auto e: g.outgoing(v)) {
30+
if (ep == graph::opposite_idx(e)) {
31+
continue;
32+
}
33+
node_index u = g.edge(e).to;
34+
if (state[u] == unvisited) {
35+
dfs(u, e);
36+
if (low[u] >= tin[v] && state[u] != blocked) {
37+
components.new_row();
38+
collect(u);
39+
components.push(v);
40+
}
41+
low[v] = std::min(low[v], low[u]);
42+
} else {
43+
low[v] = std::min(low[v], tin[u]);
44+
}
45+
}
46+
state[v] = visited;
47+
};
48+
49+
for (auto v : g.nodes()) {
50+
if (state[v] == unvisited) {
51+
if (std::ranges::empty(g.outgoing(v))) {
52+
components.new_row();
53+
components.push(v);
54+
} else {
55+
dfs(v);
56+
}
57+
}
58+
}
59+
return components;
60+
}
61+
}
62+
63+
#endif // CP_ALGO_GRAPH_BCC_HPP

cp-algo/graph/scc.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ namespace cp_algo::graph {
1010
structures::csr<node_index> scc(graph const& g) {
1111
structures::csr<node_index> components;
1212
components.reserve_data(g.n());
13-
enum node_state { unvisited, visited, collected };
13+
enum node_state { unvisited, visited, blocked };
1414
std::vector<node_state> state(g.n());
1515
auto collect = [&](this auto &&collect, node_index v) -> void {
16-
state[v] = collected;
16+
state[v] = blocked;
1717
components.push(v);
1818
for(auto e: g.outgoing(v)) {
1919
node_index u = g.edge(e).to;
20-
if (state[u] != collected) {
20+
if (state[u] != blocked) {
2121
collect(u);
2222
}
2323
}

verify/graph/2cc.test.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// @brief Two-Edge-Connected Components
2+
#define PROBLEM "https://judge.yosupo.jp/problem/two_edge_connected_components"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include <iostream>
5+
#include "blazingio/blazingio.min.hpp"
6+
#include "cp-algo/graph/2cc.hpp"
7+
#include <bits/stdc++.h>
8+
9+
using namespace std;
10+
using namespace cp_algo::graph;
11+
12+
void solve() {
13+
int n, m;
14+
cin >> n >> m;
15+
graph g(n);
16+
g.read_edges(m);
17+
auto comps = two_edge_connected_components(g);
18+
cout << size(comps) << '\n';
19+
for(auto const& comp: comps.rows()) {
20+
cout << size(comp) << ' ';
21+
for(auto v: comp) {
22+
cout << v << ' ';
23+
}
24+
cout << '\n';
25+
}
26+
}
27+
28+
signed main() {
29+
//freopen("input.txt", "r", stdin);
30+
ios::sync_with_stdio(0);
31+
cin.tie(0);
32+
int t = 1;
33+
//cin >> t;
34+
while(t--) {
35+
solve();
36+
}
37+
}

verify/graph/bcc.test.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// @brief Biconnected Components
2+
#define PROBLEM "https://judge.yosupo.jp/problem/biconnected_components"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include <iostream>
5+
#include "blazingio/blazingio.min.hpp"
6+
#include "cp-algo/graph/bcc.hpp"
7+
#include <bits/stdc++.h>
8+
9+
using namespace std;
10+
using namespace cp_algo::graph;
11+
12+
void solve() {
13+
int n, m;
14+
cin >> n >> m;
15+
graph g(n);
16+
g.read_edges(m);
17+
auto comps = biconnected_components(g);
18+
cout << size(comps) << '\n';
19+
for(auto const& comp: comps.rows()) {
20+
cout << size(comp) << ' ';
21+
for(auto v: comp) {
22+
cout << v << ' ';
23+
}
24+
cout << '\n';
25+
}
26+
}
27+
28+
signed main() {
29+
//freopen("input.txt", "r", stdin);
30+
ios::sync_with_stdio(0);
31+
cin.tie(0);
32+
int t = 1;
33+
//cin >> t;
34+
while(t--) {
35+
solve();
36+
}
37+
}

0 commit comments

Comments
 (0)