diff --git a/config.yml b/config.yml index 5611da149..c61a135ca 100644 --- a/config.yml +++ b/config.yml @@ -140,6 +140,9 @@ notebook: - dsu_weighted: 带权并查集 code_ext: hpp test_ext: cpp + - dsu_delineation: 并查集分划 + code_ext: hpp + test_ext: cpp - st_array: ST 表 - 数列 code_ext: hpp test_ext: cpp @@ -167,9 +170,6 @@ notebook: - persistent_segtree: 可持久化线段树 code_ext: hpp test_ext: cpp - - hld: 重链剖分 - code_ext: hpp - test_ext: cpp - ostree: 顺序统计树(multiset) code_ext: hpp test_ext: cpp @@ -522,9 +522,6 @@ notebook: - johnson: 全源最短路(Johnson) code_ext: hpp test_ext: cpp - - kosaraju: 强连通分量(Kosaraju) - code_ext: hpp - test_ext: cpp - path: 求两点间的一条简单路径 code_ext: hpp test_ext: cpp @@ -537,6 +534,9 @@ notebook: - ringcnt4: 无向图四元环计数 code_ext: hpp test_ext: cpp + - kosaraju: 强连通分量(Kosaraju) + code_ext: hpp + test_ext: cpp - tarjan: 强连通分量(tarjan) code_ext: hpp test_ext: cpp @@ -546,6 +546,9 @@ notebook: - e_bcc: 边双连通分量 code_ext: hpp test_ext: cpp + - e_tcc: 边三连通分量 + code_ext: hpp + test_ext: cpp - dinic: 最大流(Dinic) code_ext: hpp test_ext: cpp @@ -616,6 +619,9 @@ notebook: - tree_top: 树的 top 数组 code_ext: hpp test_ext: cpp + - hld: 重链剖分 + code_ext: hpp + test_ext: cpp - lca_hld: 树链剖分求 LCA code_ext: hpp test_ext: cpp diff --git a/img/luogu-P6658-1.png b/img/luogu-P6658-1.png new file mode 100644 index 000000000..90815b784 Binary files /dev/null and b/img/luogu-P6658-1.png differ diff --git a/src/code/ds/dsu_basic.hpp b/src/code/ds/dsu_basic.hpp index 382a2497f..363eb30cd 100644 --- a/src/code/ds/dsu_basic.hpp +++ b/src/code/ds/dsu_basic.hpp @@ -13,6 +13,7 @@ class dsu_basic { CEXPE dsu_basic(u32 sz) NE : p(sz, -1) {} CEXP i32 find(u32 x) NE { return p[x] < 0 ? (i32)x : p[x] = find((u32)p[x]); } + CEXP u32 size() CNE { return (u32)p.size(); } CEXP u32 size(u32 x) NE { return (u32)-p[(u32)find(x)]; } CEXP bool same(u32 x, u32 y) NE { return find(x) == find(y); } CEXP bool merge(u32 x, u32 y) NE { diff --git a/src/code/ds/dsu_delineation.hpp b/src/code/ds/dsu_delineation.hpp new file mode 100644 index 000000000..494a2e947 --- /dev/null +++ b/src/code/ds/dsu_delineation.hpp @@ -0,0 +1,19 @@ +#ifndef TIFALIBS_DS_DSU_DELINEATION +#define TIFALIBS_DS_DSU_DELINEATION + +#include "../util/traits.hpp" + +namespace tifa_libs::ds { + +CEXP vvecu dsu_delineation(dsu_c auto& dsu) NE { + const u32 n = dsu.size(); + vvecu mp(n); + flt_ (u32, u, 0, n) mp[(u32)dsu.find(u)].push_back(u); + auto [l, r] = remove_if(mp, [](auto CR x) { return x.empty(); }); + mp.erase(l, r); + return mp; +} + +} // namespace tifa_libs::ds + +#endif \ No newline at end of file diff --git a/src/code/ds/dsu_pd.hpp b/src/code/ds/dsu_pd.hpp index 11279c2bd..d34bb885f 100644 --- a/src/code/ds/dsu_pd.hpp +++ b/src/code/ds/dsu_pd.hpp @@ -13,6 +13,7 @@ class dsu_pd { CEXPE dsu_pd(u32 sz) NE : p(sz, -1) {} CEXP i32 find(u32 x) NE { return p[x] < 0 ? (i32)x : find((u32)p[x]); } + CEXP u32 size() CNE { return (u32)p.size(); } CEXP u32 size(u32 x) NE { return (u32)-p[(u32)find(x)]; } CEXP u32 time() NE { return (u32)edges.size(); } CEXP bool same(u32 x, u32 y) NE { return find(x) == find(y); } diff --git a/src/code/ds/dsu_weighted.hpp b/src/code/ds/dsu_weighted.hpp index 9ac437e2a..61e3431ce 100644 --- a/src/code/ds/dsu_weighted.hpp +++ b/src/code/ds/dsu_weighted.hpp @@ -18,6 +18,7 @@ class dsu_weighted { dep[x] += dep[(u32)p[x]], p[x] = _; return _; } + CEXP u32 size() CNE { return (u32)p.size(); } CEXP u32 size(u32 x) NE { return (u32)-p[(u32)find(x)]; } CEXP i64 depth(u32 x) NE { find(x); diff --git a/src/code/graph/e_tcc.hpp b/src/code/graph/e_tcc.hpp new file mode 100644 index 000000000..00fd9c1e4 --- /dev/null +++ b/src/code/graph/e_tcc.hpp @@ -0,0 +1,52 @@ +#ifndef TIFALIBS_GRAPH_E_TCC +#define TIFALIBS_GRAPH_E_TCC + +#include "../ds/dsu_basic.hpp" +#include "../ds/dsu_delineation.hpp" +#include "alist.hpp" + +namespace tifa_libs::graph { + +struct e_tcc { + vecu dfn, low, post, path, deg; + ds::dsu_basic<> dsu; + vvecu belongs; + + //! g should be undirected + template + e_tcc(alist CR g) NE : dfn(g.size(), -1_u32), low(g.size()), post(g.size()), path(g.size(), -1_u32), deg(g.size()), dsu(g.size()) { + const u32 n = g.size(); + u32 tot = -1_u32; + const auto dfs = [&](auto &&f, u32 u, u32 t = -1_u32) -> void { + u32 pc{}; + for (dfn[u] = low[u] = ++tot; u32 v : g[u]) { + if (v == u || (v == t && !pc++)) continue; + if (~dfn[v]) { + if (dfn[v] < dfn[u]) { + ++deg[u], low[u] = std::min(low[u], dfn[v]); + continue; + } + --deg[u]; + for (auto &p = path[u]; ~p && dfn[p] <= dfn[v] && dfn[v] <= post[p]; p = path[p]) + dsu.merge(u, p), deg[u] += deg[p]; + continue; + } + if (f(f, v, u); !~path[v] && deg[v] <= 1) { + low[u] = min(low[u], low[v]), deg[u] += deg[v]; + continue; + } + if (!deg[v]) v = path[v]; + if (low[u] > low[v]) low[u] = min(low[u], low[v]), swap(v, path[u]); + for (; ~v; v = path[v]) dsu.merge(u, v), deg[u] += deg[v]; + } + post[u] = tot; + }; + flt_ (u32, u, 0, n) + if (!~dfn[u]) dfs(dfs, u); + belongs = ds::dsu_delineation(dsu); + } +}; + +} // namespace tifa_libs::graph + +#endif \ No newline at end of file diff --git a/src/code/ds/hld.hpp b/src/code/tree/hld.hpp similarity index 93% rename from src/code/ds/hld.hpp rename to src/code/tree/hld.hpp index 00c36190d..554329cf9 100644 --- a/src/code/ds/hld.hpp +++ b/src/code/tree/hld.hpp @@ -1,16 +1,16 @@ #ifndef TIFALIBS_DS_HLD #define TIFALIBS_DS_HLD -#include "../tree/dfs_info.hpp" -#include "../tree/tree.hpp" -#include "../tree/tree_top.hpp" -#include "segtree.hpp" +#include "../ds/segtree.hpp" +#include "dfs_info.hpp" +#include "tree.hpp" +#include "tree_top.hpp" -namespace tifa_libs::ds { +namespace tifa_libs::graph { namespace hld_impl_ { template class hld { - segtree_impl_::segtree t; + ds::segtree_impl_::segtree t; public: using tree_info_t = graph::tree_dfs_info; diff --git a/src/code/util/traits.hpp b/src/code/util/traits.hpp index ce739dc0c..6d2f51979 100644 --- a/src/code/util/traits.hpp +++ b/src/code/util/traits.hpp @@ -24,13 +24,13 @@ template concept int_c = i128_c || imost64_c; template concept sint_c = s128_c || smost64_c; template concept uint_c = u128_c || umost64_c; template concept arithm_c = std::is_arithmetic_v || int_c; -template concept mint_c = requires(T x) { { x.mod() } -> uint_c; { x.val() } -> uint_c; }; -template concept dft_c = requires(T x, vec v, u32 n) { { x.size() } -> std::same_as; x.bzr(n); x.dif(v, n); x.dit(v, n); }; +template concept mint_c = requires(T x) { {x.mod()} -> uint_c; {x.val()} -> uint_c; }; +template concept dft_c = requires(T x, vec v, u32 n) { {x.size()} -> std::same_as; x.bzr(n); x.dif(v, n); x.dit(v, n); }; template concept ntt_c = dft_c && requires(T x) { T::max_size; T::G; }; //! weighted or unweighted template concept sparse_graph_c = requires(T g) { g.cnt_arc; g.deg_in; g.deg_out; g.size(); g.foreach(0, fn_0); } && (requires(T g) { g.add_arc(0, 0); g.add_edge(0, 0); } || requires(T g) { g.add_arc(0, 0, {}); g.add_edge(0, 0, {}); }); //! weighted or unweighted -template concept alist_c = sparse_graph_c && requires(T g) { { g[0] } -> common_range; g.build(); }; +template concept alist_c = sparse_graph_c && requires(T g) { {g[0]} -> common_range; g.build(); }; //! weighted or unweighted template concept eog_c = sparse_graph_c && requires(T g) { g.head; g.e; g.pop_startwith(0); }; //! weighted or unweighted @@ -47,8 +47,9 @@ template concept treew_c = tree_c && alistw_c; template concept tp_ds_c = requires(P p) { p->ch; std::is_array_vch)>; std::rank_vch)> == 1; }; // binary tree pointer (for DS) template concept tp2_ds_c = tp_ds_c

&& std::extent_v()->ch)> == 2; -template concept istream_c = std::derived_from || requires(T is, T& (*func)(T&)) { { is >> func } -> std::same_as; }; -template concept ostream_c = std::derived_from || requires(T os, T& (*func)(T&)) { { os << func } -> std::same_as; }; +template concept istream_c = std::derived_from || requires(T is, T& (*func)(T&)) { {is >> func} -> std::same_as; }; +template concept ostream_c = std::derived_from || requires(T os, T& (*func)(T&)) { {os << func} -> std::same_as; }; +template concept dsu_c = requires(T dsu, u32 x, u32 y) { {dsu.find(x)} -> std::same_as; {dsu.size()} -> std::same_as; {dsu.size(x)} -> std::same_as; {dsu.same(x, y)} -> std::same_as; {dsu.merge(x, y)} -> std::same_as; }; template struct to_sint : std::make_signed {}; template <> struct to_sint { using type = i128; }; diff --git a/src/doc_md/ds/dsu_delineation.md b/src/doc_md/ds/dsu_delineation.md new file mode 100644 index 000000000..3ed9e6030 --- /dev/null +++ b/src/doc_md/ds/dsu_delineation.md @@ -0,0 +1,4 @@ +--- +title: dsu_delineation +documentation_of: //src/code/ds/dsu_delineation.hpp +--- diff --git a/src/doc_md/ds/hld.md b/src/doc_md/ds/hld.md deleted file mode 100644 index 627d9f5f9..000000000 --- a/src/doc_md/ds/hld.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: hld -documentation_of: //src/code/ds/hld.hpp ---- diff --git a/src/doc_md/graph/e_tcc.md b/src/doc_md/graph/e_tcc.md new file mode 100644 index 000000000..f21aac97d --- /dev/null +++ b/src/doc_md/graph/e_tcc.md @@ -0,0 +1,4 @@ +--- +title: e_tcc +documentation_of: //src/code/graph/e_tcc.hpp +--- diff --git a/src/doc_md/tree/hld.md b/src/doc_md/tree/hld.md new file mode 100644 index 000000000..3bf26cc0a --- /dev/null +++ b/src/doc_md/tree/hld.md @@ -0,0 +1,4 @@ +--- +title: hld +documentation_of: //src/code/tree/hld.hpp +--- diff --git a/src/test_tinplate/ds/hld.cpp b/src/doc_tex/ds/dsu_delineation.tex similarity index 100% rename from src/test_tinplate/ds/hld.cpp rename to src/doc_tex/ds/dsu_delineation.tex diff --git a/src/doc_tex/graph/e_tcc.tex b/src/doc_tex/graph/e_tcc.tex new file mode 100644 index 000000000..f8d9f60b8 --- /dev/null +++ b/src/doc_tex/graph/e_tcc.tex @@ -0,0 +1,5 @@ +\paragraph{样例一图片} + +\begin{center} + \includegraphics[width=0.4\textwidth]{img/luogu-P6658-1.png} +\end{center} diff --git a/src/doc_tex/ds/hld.tex b/src/doc_tex/tree/hld.tex similarity index 100% rename from src/doc_tex/ds/hld.tex rename to src/doc_tex/tree/hld.tex diff --git a/src/meta_test/library-checker-tree/vertex_set_path_composite.cppmeta b/src/meta_test/library-checker-tree/vertex_set_path_composite.cppmeta index debdcd33c..debed0b09 100644 --- a/src/meta_test/library-checker-tree/vertex_set_path_composite.cppmeta +++ b/src/meta_test/library-checker-tree/vertex_set_path_composite.cppmeta @@ -1,6 +1,6 @@ #define PROBLEM "https://judge.yosupo.jp/problem/vertex_set_path_composite/" -#include "../../code/ds/hld.hpp" +#include "../../code/tree/hld.hpp" #include "../../code/tree/lca_hld.hpp" CEXP u32 MOD = 998244353; @@ -33,8 +33,8 @@ int main() { for (u32 i = 1, u, v; i < n; ++i) std::cin >> u >> v, tr.add_arc(u, v), tr.add_arc(v, u); tifa_libs::graph::lca_hld::tree_info_t info(tr); tifa_libs::graph::lca_hld lca(tr, info); - tifa_libs::ds::hld hld(e(), id(), tr, info, a); - tifa_libs::ds::hld hld1(e(), id(), tr, info, a); + tifa_libs::graph::hld hld(e(), id(), tr, info, a); + tifa_libs::graph::hld hld1(e(), id(), tr, info, a); for (u32 i = 0, opt; i < q; ++i) { std::cin >> opt; if (opt == 0) { diff --git a/src/test_cpverifier/aizu-grl/grl_5_d.test.cpp b/src/test_cpverifier/aizu-grl/grl_5_d.test.cpp new file mode 100644 index 000000000..1d6240446 --- /dev/null +++ b/src/test_cpverifier/aizu-grl/grl_5_d.test.cpp @@ -0,0 +1,39 @@ +#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/all/GRL_5_D" + +#include "../../code/io/fastin.hpp" +#include "../../code/io/fastout.hpp" +#include "../../code/tree/hld.hpp" + +using T = std::pair; +using F = i64; + +T op(T a, T b) { return T{a.first + b.first, a.second + b.second}; } +void mapping(T& a, F f) { a.first += f; } +void composition(F& f, F g) { f += g; } + +int main() { + u32 n, q; + tifa_libs::fin >> n; + vecii b(n, 0); + vec a(n); + tifa_libs::graph::tree tr_(n); + for (u32 u = 0, k; u < n; ++u) { + tifa_libs::fin >> k; + for (u32 i = 0, v; i < k; ++i) tifa_libs::fin >> v, tr_.add_edge(u, v); + } + tifa_libs::graph::hld tr({0, 0}, 0, tr_); + flt_ (u32, i, 0, n) a[tr.info.dfn[i]].first = b[i], a[tr.info.dfn[i]].second = 1; + tr.build(a); + tifa_libs::fin >> q; + for (u32 i = 0, opt, u; i < q; ++i) { + tifa_libs::fin >> opt >> u; + if (opt == 0) { + i64 x; + tifa_libs::fin >> x; + tr.node_update((u32)u, x); + } else { + tifa_libs::fout << tr.chain_query((u32)u, 0).first << '\n'; + } + } + return 0; +} diff --git a/src/test_cpverifier/aizu-grl/grl_5_e.test.cpp b/src/test_cpverifier/aizu-grl/grl_5_e.test.cpp new file mode 100644 index 000000000..e00de67bf --- /dev/null +++ b/src/test_cpverifier/aizu-grl/grl_5_e.test.cpp @@ -0,0 +1,40 @@ +#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/all/GRL_5_E" + +#include "../../code/io/fastin.hpp" +#include "../../code/io/fastout.hpp" +#include "../../code/tree/hld.hpp" + +using T = std::pair; +using F = i64; + +T op(T a, T b) { return T{a.first + b.first, a.second + b.second}; } +void mapping(T& a, F f) { a.first += f * a.second; } +void composition(F& f, F g) { f += g; } + +int main() { + u32 n, q; + tifa_libs::fin >> n; + vecii b(n, 0); + vec a(n); + tifa_libs::graph::tree tr_(n); + for (u32 u = 0, k; u < n; ++u) { + tifa_libs::fin >> k; + for (u32 i = 0, v; i < k; ++i) tifa_libs::fin >> v, tr_.add_edge(u, v); + } + tifa_libs::graph::hld tr({0, 0}, 0, tr_); + flt_ (u32, i, 0, n) a[tr.info.dfn[i]].first = b[i], a[tr.info.dfn[i]].second = 1; + tr.build(a); + tifa_libs::fin >> q; + for (u32 i = 0, opt, u; i < q; ++i) { + tifa_libs::fin >> opt >> u; + if (opt == 0) { + i64 x; + tifa_libs::fin >> x; + tr.chain_update((u32)u, 0, x); + tr.node_update(0, -x); + } else { + tifa_libs::fout << tr.chain_query((u32)u, 0).first << '\n'; + } + } + return 0; +} diff --git a/src/test_cpverifier/library-checker-graph/three_edge_connected_components.test.cpp b/src/test_cpverifier/library-checker-graph/three_edge_connected_components.test.cpp new file mode 100644 index 000000000..5eb2024ad --- /dev/null +++ b/src/test_cpverifier/library-checker-graph/three_edge_connected_components.test.cpp @@ -0,0 +1,23 @@ +#define PROBLEM "https://judge.yosupo.jp/problem/three_edge_connected_components" + +#include "../../code/graph/e_tcc.hpp" + +int main() { + std::cin.tie(nullptr)->std::ios::sync_with_stdio(false); + u32 n, m; + std::cin >> n >> m; + tifa_libs::graph::alist g(n); + for (u32 i = 0, u, v; i < m; ++i) { + std::cin >> u >> v; + g.add_edge(u, v); + } + tifa_libs::graph::e_tcc tcc(g); + std::cout << tcc.belongs.size() << '\n'; + for (auto &&b : tcc.belongs) { + std::cout << b.size(); + for (auto x : b) + std::cout << ' ' << x; + std::cout << '\n'; + } + return 0; +} diff --git a/src/test_cpverifier/library-checker-tree/vertex_add_path_sum.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_add_path_sum.test.cpp index 88809a147..59bbfd768 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_add_path_sum.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_add_path_sum.test.cpp @@ -1,8 +1,8 @@ #define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_path_sum" -#include "../../code/ds/hld.hpp" #include "../../code/io/fastin.hpp" #include "../../code/io/fastout.hpp" +#include "../../code/tree/hld.hpp" using T = std::pair; using F = i64; @@ -19,7 +19,7 @@ int main() { for (auto& x : b) tifa_libs::fin >> x; tifa_libs::graph::tree tr_(n); for (u32 i = 1, u, v; i < n; ++i) tifa_libs::fin >> u >> v, tr_.add_arc((u32)u, (u32)v), tr_.add_arc((u32)v, (u32)u); - tifa_libs::ds::hld tr({0, 0}, 0, tr_); + tifa_libs::graph::hld tr({0, 0}, 0, tr_); flt_ (u32, i, 0, n) a[tr.info.dfn[i]].first = b[i], a[tr.info.dfn[i]].second = 1; tr.build(a); for (u32 i = 0, opt, u; i < q; ++i) { diff --git a/src/test_cpverifier/library-checker-tree/vertex_add_subtree_sum.hld.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_add_subtree_sum.hld.test.cpp index 35642b41b..3f648556d 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_add_subtree_sum.hld.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_add_subtree_sum.hld.test.cpp @@ -1,8 +1,8 @@ #define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_subtree_sum" -#include "../../code/ds/hld.hpp" #include "../../code/io/fastin.hpp" #include "../../code/io/fastout.hpp" +#include "../../code/tree/hld.hpp" using T = std::pair; using F = i64; @@ -19,7 +19,7 @@ int main() { for (auto& x : b) tifa_libs::fin >> x; tifa_libs::graph::tree tr_(n); for (u32 i = 1, p; i < n; ++i) tifa_libs::fin >> p, tr_.add_arc((u32)p, (u32)i); - tifa_libs::ds::hld tr({0, 0}, 0, tr_); + tifa_libs::graph::hld tr({0, 0}, 0, tr_); flt_ (u32, i, 0, n) a[tr.info.dfn[i]].first = b[i], a[tr.info.dfn[i]].second = 1; tr.build(a); for (u32 i = 0, opt, u; i < q; ++i) { diff --git a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d31.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d31.test.cpp index 81e1f8e97..570ddf903 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d31.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d31.test.cpp @@ -1,7 +1,7 @@ #define AUTO_GENERATED #define PROBLEM "https://judge.yosupo.jp/problem/vertex_set_path_composite/" -#include "../../code/ds/hld.hpp" +#include "../../code/tree/hld.hpp" #include "../../code/tree/lca_hld.hpp" CEXP u32 MOD = 998244353; @@ -36,8 +36,8 @@ int main() { for (u32 i = 1, u, v; i < n; ++i) std::cin >> u >> v, tr.add_arc(u, v), tr.add_arc(v, u); tifa_libs::graph::lca_hld::tree_info_t info(tr); tifa_libs::graph::lca_hld lca(tr, info); - tifa_libs::ds::hld hld(e(), id(), tr, info, a); - tifa_libs::ds::hld hld1(e(), id(), tr, info, a); + tifa_libs::graph::hld hld(e(), id(), tr, info, a); + tifa_libs::graph::hld hld1(e(), id(), tr, info, a); for (u32 i = 0, opt; i < q; ++i) { std::cin >> opt; if (opt == 0) { diff --git a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d63.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d63.test.cpp index e0dbb3422..d320bd145 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d63.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mintd-d63.test.cpp @@ -1,7 +1,7 @@ #define AUTO_GENERATED #define PROBLEM "https://judge.yosupo.jp/problem/vertex_set_path_composite/" -#include "../../code/ds/hld.hpp" +#include "../../code/tree/hld.hpp" #include "../../code/tree/lca_hld.hpp" CEXP u32 MOD = 998244353; @@ -36,8 +36,8 @@ int main() { for (u32 i = 1, u, v; i < n; ++i) std::cin >> u >> v, tr.add_arc(u, v), tr.add_arc(v, u); tifa_libs::graph::lca_hld::tree_info_t info(tr); tifa_libs::graph::lca_hld lca(tr, info); - tifa_libs::ds::hld hld(e(), id(), tr, info, a); - tifa_libs::ds::hld hld1(e(), id(), tr, info, a); + tifa_libs::graph::hld hld(e(), id(), tr, info, a); + tifa_libs::graph::hld hld1(e(), id(), tr, info, a); for (u32 i = 0, opt; i < q; ++i) { std::cin >> opt; if (opt == 0) { diff --git a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s30.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s30.test.cpp index 1b35b7c14..775df5726 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s30.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s30.test.cpp @@ -1,7 +1,7 @@ #define AUTO_GENERATED #define PROBLEM "https://judge.yosupo.jp/problem/vertex_set_path_composite/" -#include "../../code/ds/hld.hpp" +#include "../../code/tree/hld.hpp" #include "../../code/tree/lca_hld.hpp" CEXP u32 MOD = 998244353; @@ -35,8 +35,8 @@ int main() { for (u32 i = 1, u, v; i < n; ++i) std::cin >> u >> v, tr.add_arc(u, v), tr.add_arc(v, u); tifa_libs::graph::lca_hld::tree_info_t info(tr); tifa_libs::graph::lca_hld lca(tr, info); - tifa_libs::ds::hld hld(e(), id(), tr, info, a); - tifa_libs::ds::hld hld1(e(), id(), tr, info, a); + tifa_libs::graph::hld hld(e(), id(), tr, info, a); + tifa_libs::graph::hld hld1(e(), id(), tr, info, a); for (u32 i = 0, opt; i < q; ++i) { std::cin >> opt; if (opt == 0) { diff --git a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s63.test.cpp b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s63.test.cpp index 048d7a63d..5e6b826ea 100644 --- a/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s63.test.cpp +++ b/src/test_cpverifier/library-checker-tree/vertex_set_path_composite.mints-s63.test.cpp @@ -1,7 +1,7 @@ #define AUTO_GENERATED #define PROBLEM "https://judge.yosupo.jp/problem/vertex_set_path_composite/" -#include "../../code/ds/hld.hpp" +#include "../../code/tree/hld.hpp" #include "../../code/tree/lca_hld.hpp" CEXP u32 MOD = 998244353; @@ -35,8 +35,8 @@ int main() { for (u32 i = 1, u, v; i < n; ++i) std::cin >> u >> v, tr.add_arc(u, v), tr.add_arc(v, u); tifa_libs::graph::lca_hld::tree_info_t info(tr); tifa_libs::graph::lca_hld lca(tr, info); - tifa_libs::ds::hld hld(e(), id(), tr, info, a); - tifa_libs::ds::hld hld1(e(), id(), tr, info, a); + tifa_libs::graph::hld hld(e(), id(), tr, info, a); + tifa_libs::graph::hld hld1(e(), id(), tr, info, a); for (u32 i = 0, opt; i < q; ++i) { std::cin >> opt; if (opt == 0) { diff --git a/src/test_tinplate/ds/dsu_delineation.cpp b/src/test_tinplate/ds/dsu_delineation.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/test_tinplate/graph/e_tcc.cpp b/src/test_tinplate/graph/e_tcc.cpp new file mode 100644 index 000000000..aada72112 --- /dev/null +++ b/src/test_tinplate/graph/e_tcc.cpp @@ -0,0 +1,104 @@ +#define PROBLEM "https://www.luogu.com.cn/problem/P6658" + +#include "../../code/graph/e_tcc.hpp" + +int main() { + std::cin.tie(nullptr)->std::ios::sync_with_stdio(false); + u32 n, m; + std::cin >> n >> m; + tifa_libs::graph::alist g(n); + for (u32 i = 0, u, v; i < m; ++i) { + std::cin >> u >> v; + --u, --v; + g.add_edge(u, v); + } + tifa_libs::graph::e_tcc tcc(g); + for (auto &b : tcc.belongs) std::ranges::sort(b); + std::ranges::sort(tcc.belongs); + std::cout << tcc.belongs.size() << '\n'; + for (auto &&b : tcc.belongs) { + for (auto x : b) + std::cout << x + 1 << ' '; + std::cout << '\n'; + } + return 0; +} + +/* +对于一张无向图 $G = (V, E)$ +- 我们称两个点 $u, v ~ (u, v \in V, u \neq v)$ 是边三连通的, 当且仅当存在三条从 $u$ 出发到达 $v$ 的, 相互没有公共边的路径 +- 我们称一个点集 $U ~ (U \subseteq V)$ 是边三连通分量, 当且仅当对于任意两个点 $u', v' ~ (u', v' \in U, u' \neq v')$ 都是边三连通的 +- 我们称一个边三连通分量 $S$ 是极大边三连通分量, 当且仅当不存在 $u \not \in S$ 且 $u \in V$, 使得 $S \cup \{u\}$ 也是边三连通分量 +给出一个 $n$ 个点, $m$ 条边的无向图 $G = (V, E)$, $V = \{1, 2, \ldots, n\}$, 请求出其所有的极大边三连通分量 + +## 输入 +第一行输入两个整数 $n, m$, 表示点数、边数 +接下来 $m$ 行, 每行输入两个数 $u, v$, 表示图上的一条边 +$1 \le n, m \le 5 \times 10 ^ 5$, $1 \le u, v \le n$. 可能有重边和自环 + +## 输出 +第一行输出一个整数 $s$, 表示极大边三连通分量个数 +接下来输出 $s$ 行, 每行若干整数, 表示一个极大边三连通分量内所有点 +对于单个极大边三连通分量, 请将点按照标号升序输出对于所有极大边三连通分量, 请按照点集内编号最小的点升序输出 + +## 提示 +样例一图片见 PDF +如图, $1 \to 3$ 共有 $(1, 2, 3)$, $(1, 3)$, $(1, 4, 3)$ 三条路径, 它们互相都没有相交的边. 因此 $1$ 与 $3$ 在同一个边三连通分量中 +由于 $2$, $4$ 点度都只有 $2$, 不可能有三条边不相交的到其它点的路径, 因此它们自己形成边三联通分量 +*/ + +/* +4 5 +1 3 +1 2 +4 1 +3 2 +3 4 +================ +3 +1 3 +2 +4 +*/ + +/* +17 29 +1 2 +1 10 +1 10 +2 3 +2 8 +3 4 +3 5 +4 6 +4 6 +5 6 +5 6 +5 7 +7 8 +7 11 +7 12 +7 17 +7 17 +8 9 +9 10 +11 12 +11 17 +12 13 +12 16 +13 14 +13 15 +13 16 +14 15 +14 16 +15 16 +=============== +7 +1 10 +2 8 +3 4 5 6 +7 11 17 +9 +12 +13 14 15 16 +*/ \ No newline at end of file diff --git a/src/test_tinplate/tree/hld.cpp b/src/test_tinplate/tree/hld.cpp new file mode 100644 index 000000000..e69de29bb