This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub hitonanode/cplib-cpp
#include "../incremental_bridge_connectivity.hpp" #include <algorithm> #include <iostream> #include <vector> #define PROBLEM "https://judge.yosupo.jp/problem/two_edge_connected_components" using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int V, E; cin >> V >> E; IncrementalBridgeConnectivity graph(V); while (E--) { int s, t; cin >> s >> t; graph.add_edge(s, t); } vector<vector<int>> ret(V); for (int i = 0; i < V; i++) { ret[graph.find(i)].emplace_back(i); } int K = count_if(ret.begin(), ret.end(), [](const vector<int> &v) { return v.size() > 0; }); cout << K << '\n'; for (const auto &vec : ret) { if (vec.size()) { cout << vec.size(); for (auto x : vec) { cout << ' ' << x; } cout << '\n'; } } }
#line 2 "unionfind/unionfind.hpp" #include <algorithm> #include <numeric> #include <utility> #include <vector> // CUT begin // UnionFind Tree (0-indexed), based on size of each disjoint set struct UnionFind { std::vector<int> par, cou; UnionFind(int N = 0) : par(N), cou(N, 1) { iota(par.begin(), par.end(), 0); } int find(int x) { return (par[x] == x) ? x : (par[x] = find(par[x])); } bool unite(int x, int y) { x = find(x), y = find(y); if (x == y) return false; if (cou[x] < cou[y]) std::swap(x, y); par[y] = x, cou[x] += cou[y]; return true; } int count(int x) { return cou[find(x)]; } bool same(int x, int y) { return find(x) == find(y); } std::vector<std::vector<int>> groups() { std::vector<std::vector<int>> ret(par.size()); for (int i = 0; i < int(par.size()); ++i) ret[find(i)].push_back(i); ret.erase(std::remove_if(ret.begin(), ret.end(), [&](const std::vector<int> &v) { return v.empty(); }), ret.end()); return ret; } }; #line 3 "graph/incremental_bridge_connectivity.hpp" #include <cassert> #line 5 "graph/incremental_bridge_connectivity.hpp" #include <unordered_set> #line 7 "graph/incremental_bridge_connectivity.hpp" // CUT begin // Incremental Bridge-Connectivity // two-edge-connected components // Reference: <https://scrapbox.io/data-structures/Incremental_Bridge-Connectivity> // <https://ei1333.github.io/library/graph/connected-components/incremental-bridge-connectivity.cpp> struct IncrementalBridgeConnectivity { int V; int nb_bridge; UnionFind con, bicon; std::vector<int> bbf; int _bicon_par(int x) { return bbf[x] == -1 ? -1 : bicon.find(bbf[x]); } int _lca(int x, int y) { std::unordered_set<int> us; while (true) { if (x != -1) { if (!us.insert(x).second) { return x; } x = _bicon_par(x); } std::swap(x, y); } } void _compress(int now, int lca) { while (bicon.find(now) != bicon.find(lca)) { int nxt = _bicon_par(now); bbf[now] = bbf[lca], bicon.unite(now, lca), now = nxt, nb_bridge--; } } IncrementalBridgeConnectivity(int v = 0) : V(v), nb_bridge(0), con(v), bicon(v), bbf(v, -1) {} void add_edge(int u, int v) { assert(u >= 0 and u < V); assert(v >= 0 and v < V); u = bicon.find(u), v = bicon.find(v); if (con.find(u) == con.find(v)) { int lca = _lca(u, v); _compress(u, lca), _compress(v, lca); } else { if (con.count(u) > con.count(v)) std::swap(u, v); for (int now = u, pre = v; now != -1;) { int nxt = _bicon_par(now); bbf[now] = pre, pre = now, now = nxt; } con.unite(u, v), nb_bridge++; } } int count_bridge() const { return nb_bridge; } bool two_edge_connected(int x, int y) { return bicon.same(x, y); } int find(int x) { return bicon.find(x); } }; #line 3 "graph/test/incremental-bridge-connectivity.test.cpp" #include <iostream> #line 5 "graph/test/incremental-bridge-connectivity.test.cpp" #define PROBLEM "https://judge.yosupo.jp/problem/two_edge_connected_components" using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int V, E; cin >> V >> E; IncrementalBridgeConnectivity graph(V); while (E--) { int s, t; cin >> s >> t; graph.add_edge(s, t); } vector<vector<int>> ret(V); for (int i = 0; i < V; i++) { ret[graph.find(i)].emplace_back(i); } int K = count_if(ret.begin(), ret.end(), [](const vector<int> &v) { return v.size() > 0; }); cout << K << '\n'; for (const auto &vec : ret) { if (vec.size()) { cout << vec.size(); for (auto x : vec) { cout << ' ' << x; } cout << '\n'; } } }