Skip to content

Commit

Permalink
refactor: better e_bcc
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Feb 27, 2025
1 parent 4669c0d commit 10c45fb
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 44 deletions.
53 changes: 22 additions & 31 deletions src/code/graph/e_bcc.hpp
Original file line number Diff line number Diff line change
@@ -1,45 +1,36 @@
#ifndef TIFALIBS_GRAPH_E_BCC
#define TIFALIBS_GRAPH_E_BCC

#include "../util/util.hpp"
#include "eog.hpp"

namespace tifa_libs::graph {

template <class EW>
class e_bcc {
vvec<EW> CR g;

public:
u32 id;
vecu ebcc_id, dfn, low;
vecb cut;
struct e_bcc {
vecu dfn, low;
vvecu belongs;

//! EW need rev_edge
CEXPE e_bcc(vvec<EW> CR G) NE : g(G) { build(); }

CEXP void build() NE {
u32 cnt = 0, n = u32(g.size());
id = 0, dfn = low = ebcc_id = vecu(n, n), cut = vecb(n, 0);
vecu s;
auto f = [&](auto &&f, u32 u, u32 fa, u32 inv_from) NE -> void {
dfn[u] = low[u] = cnt++, s.push_back(u);
flt_ (u32, i, 0, (u32)g[u].size()) {
auto v = g[u][i];
if (v.to == fa && i == inv_from) continue;
if (dfn[v.to] == n) f(f, v.to, u, v.inv), low[u] = min(low[u], low[v.to]);
else low[u] = min(low[u], dfn[v.to]);
}
//! g should be undirect
template <bool with_deg>
CEXP e_bcc(eog<with_deg> CR g) NE : dfn(g.v_cnt()), low(g.v_cnt()) {
vecu stk;
u32 tot = 0;
auto tarjan = [&](auto&& f, u32 u, u32 fa_eid) -> void {
dfn[u] = low[u] = ++tot;
stk.push_back(u);
g.foreach(u, [&](u32 eid, u32 v, u32) {
if (!dfn[v]) f(f, v, eid), low[u] = min(low[u], low[v]);
else if (eid != fa_eid && eid != (fa_eid ^ 1)) low[u] = min(low[u], dfn[v]);
});
if (low[u] == dfn[u]) {
belongs.push_back(vecu());
do {
const u32 v = s.back();
if (s.pop_back(), ebcc_id[v] = id, belongs[id].push_back(v); v == u) return void(++id);
} while (1);
vecu res;
u32 p;
do res.push_back(p = stk.back()), stk.pop_back();
while (u != p);
belongs.emplace_back(std::move(res));
}
};
flt_ (u32, i, 0, n)
if (dfn[i] == n) f(f, i, i, -1_u32);
flt_ (u32, i, 0, g.v_cnt())
if (!dfn[i]) tarjan(tarjan, i, -1_u32);
}
};

Expand Down
8 changes: 8 additions & 0 deletions src/code/graph/eog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@ struct eog {
CEXPE eog(u32 n = 0) NE : head(n, -1_u32), e(), cnt_arc{0}, deg_in(0), deg_out(0) {
if CEXP (with_deg) deg_in.resize(n), deg_out.resize(n);
}
CEXP u32 v_cnt() CNE { return (u32)head.size(); }
CEXP u32 arc_cnt() CNE { return (u32)e.size(); }
CEXP void add_arc(u32 u, u32 v) NE {
e.emplace_back(v, head[u]), head[u] = u32(e.size() - 1);
if CEXP (++cnt_arc; with_deg) ++deg_in[v], ++deg_out[u];
}
CEXP void add_edge(u32 u, u32 v) NE { add_arc(u, v), add_arc(v, u); }
CEXP void pop_startwith(u32 now) NE {
if CEXP (--cnt_arc; with_deg) --deg_in[e[head[now]].first], --deg_out[now];
head[now] = e[head[now]].second;
}
template <class F>
requires requires(F f, u32 eid, u32 to, u32 next) { f(eid, to, next); }
CEXP void foreach(u32 u, F&& f) CNE {
for (u32 i = head[u]; ~i; i = e[i].second) f(i, e[i].first, e[i].second);
}
};
template <class T, bool with_deg = false>
struct eogw {
Expand Down
2 changes: 1 addition & 1 deletion src/code/graph/v_bcc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct v_bcc {
vvecu belongs;
vecb cut;

//! G should be undirect
//! g should be undirect
template <bool with_deg>
CEXP v_bcc(alist<with_deg> CR g) NE : dfn(g.size()), low(g.size()) {
if CEXP (get_cut) cut = vecb(g.size());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#define PROBLEM "https://judge.yosupo.jp/problem/two_edge_connected_components"

#include "../../code/graph/e_bcc.hpp"

int main() {
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
u32 n, m;
std::cin >> n >> m;
tifa_libs::graph::eog g(n);
for (u32 i = 0, u, v; i < m; ++i) {
std::cin >> u >> v;
g.add_edge(u, v);
}
tifa_libs::graph::e_bcc bcc(g);
std::cout << bcc.belongs.size() << '\n';
for (auto&& b : bcc.belongs) {
for (std::cout << b.size(); auto x : b)
std::cout << ' ' << x;
std::cout << '\n';
}
return 0;
}
20 changes: 8 additions & 12 deletions src/test_tinplate/graph/e_bcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,16 @@ int main() {
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
u32 n, m;
std::cin >> n >> m;
struct EW {
u32 to, inv;
};
vvec<EW> e(n);
tifa_libs::graph::eog g(n);
for (u32 i = 0, u, v; i < m; ++i) {
std::cin >> u >> v, --u, --v;
if (u == v) continue;
u32 tem1 = u32(e[u].size()), tem2 = u32(e[v].size());
e[u].push_back({v, tem2}), e[v].push_back({u, tem1});
std::cin >> u >> v;
--u, --v;
g.add_edge(u, v);
}
tifa_libs::graph::e_bcc<EW> bcc(e);
std::cout << bcc.id << '\n';
for (u32 i = 0; i < bcc.id; ++i) {
for (std::cout << bcc.belongs[i].size() << ' '; auto x : bcc.belongs[i])
tifa_libs::graph::e_bcc bcc(g);
std::cout << bcc.belongs.size() << '\n';
for (auto&& b : bcc.belongs) {
for (std::cout << b.size() << ' '; auto x : b)
std::cout << x + 1 << ' ';
std::cout << '\n';
}
Expand Down

0 comments on commit 10c45fb

Please sign in to comment.