Skip to content

Commit

Permalink
refactor: move hld
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Feb 28, 2025
1 parent 3a2e480 commit f78d1a0
Show file tree
Hide file tree
Showing 29 changed files with 340 additions and 40 deletions.
18 changes: 12 additions & 6 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
Binary file added img/luogu-P6658-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/code/ds/dsu_basic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions src/code/ds/dsu_delineation.hpp
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions src/code/ds/dsu_pd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
1 change: 1 addition & 0 deletions src/code/ds/dsu_weighted.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
52 changes: 52 additions & 0 deletions src/code/graph/e_tcc.hpp
Original file line number Diff line number Diff line change
@@ -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 <bool with_deg>
e_tcc(alist<with_deg> 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
12 changes: 6 additions & 6 deletions src/code/ds/hld.hpp → src/code/tree/hld.hpp
Original file line number Diff line number Diff line change
@@ -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 <bool enable_tag, class T, auto op, class F, auto mapping, auto composition>
class hld {
segtree_impl_::segtree<enable_tag, T, op, F, mapping, composition> t;
ds::segtree_impl_::segtree<enable_tag, T, op, F, mapping, composition> t;

public:
using tree_info_t = graph::tree_dfs_info<graph::tree, graph::tdi_dfn, graph::tdi_maxson, graph::tdi_dep, graph::tdi_fa>;
Expand Down
11 changes: 6 additions & 5 deletions src/code/util/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ template <class T> concept int_c = i128_c<T> || imost64_c<T>;
template <class T> concept sint_c = s128_c<T> || smost64_c<T>;
template <class T> concept uint_c = u128_c<T> || umost64_c<T>;
template <class T> concept arithm_c = std::is_arithmetic_v<T> || int_c<T>;
template <class T> concept mint_c = requires(T x) { { x.mod() } -> uint_c; { x.val() } -> uint_c; };
template <class T> concept dft_c = requires(T x, vec<TPN T::data_t> v, u32 n) { { x.size() } -> std::same_as<u32>; x.bzr(n); x.dif(v, n); x.dit(v, n); };
template <class T> concept mint_c = requires(T x) { {x.mod()} -> uint_c; {x.val()} -> uint_c; };
template <class T> concept dft_c = requires(T x, vec<TPN T::data_t> v, u32 n) { {x.size()} -> std::same_as<u32>; x.bzr(n); x.dif(v, n); x.dit(v, n); };
template <class T> concept ntt_c = dft_c<T> && requires(T x) { T::max_size; T::G; };
//! weighted or unweighted
template <class T> 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 <class T> concept alist_c = sparse_graph_c<T> && requires(T g) { { g[0] } -> common_range; g.build(); };
template <class T> concept alist_c = sparse_graph_c<T> && requires(T g) { {g[0]} -> common_range; g.build(); };
//! weighted or unweighted
template <class T> concept eog_c = sparse_graph_c<T> && requires(T g) { g.head; g.e; g.pop_startwith(0); };
//! weighted or unweighted
Expand All @@ -47,8 +47,9 @@ template <class T> concept treew_c = tree_c<T> && alistw_c<T>;
template <class P> concept tp_ds_c = requires(P p) { p->ch; std::is_array_v<decltype(p->ch)>; std::rank_v<decltype(p->ch)> == 1; };
// binary tree pointer (for DS)
template <class P> concept tp2_ds_c = tp_ds_c<P> && std::extent_v<decltype(std::declval<P>()->ch)> == 2;
template <class T> concept istream_c = std::derived_from<T, std::istream> || requires(T is, T& (*func)(T&)) { { is >> func } -> std::same_as<T&>; };
template <class T> concept ostream_c = std::derived_from<T, std::ostream> || requires(T os, T& (*func)(T&)) { { os << func } -> std::same_as<T&>; };
template <class T> concept istream_c = std::derived_from<T, std::istream> || requires(T is, T& (*func)(T&)) { {is >> func} -> std::same_as<T&>; };
template <class T> concept ostream_c = std::derived_from<T, std::ostream> || requires(T os, T& (*func)(T&)) { {os << func} -> std::same_as<T&>; };
template <class T> concept dsu_c = requires(T dsu, u32 x, u32 y) { {dsu.find(x)} -> std::same_as<i32>; {dsu.size()} -> std::same_as<u32>; {dsu.size(x)} -> std::same_as<u32>; {dsu.same(x, y)} -> std::same_as<bool>; {dsu.merge(x, y)} -> std::same_as<bool>; };

template <class T> struct to_sint : std::make_signed<T> {};
template <> struct to_sint<u128> { using type = i128; };
Expand Down
4 changes: 4 additions & 0 deletions src/doc_md/ds/dsu_delineation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: dsu_delineation
documentation_of: //src/code/ds/dsu_delineation.hpp
---
4 changes: 0 additions & 4 deletions src/doc_md/ds/hld.md

This file was deleted.

4 changes: 4 additions & 0 deletions src/doc_md/graph/e_tcc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: e_tcc
documentation_of: //src/code/graph/e_tcc.hpp
---
4 changes: 4 additions & 0 deletions src/doc_md/tree/hld.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: hld
documentation_of: //src/code/tree/hld.hpp
---
File renamed without changes.
5 changes: 5 additions & 0 deletions src/doc_tex/graph/e_tcc.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
\paragraph{样例一图片}

\begin{center}
\includegraphics[width=0.4\textwidth]{img/luogu-P6658-1.png}
\end{center}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<T, op_ba, F, mapping, composition> hld(e(), id(), tr, info, a);
tifa_libs::ds::hld<T, op_ab, F, mapping, composition> hld1(e(), id(), tr, info, a);
tifa_libs::graph::hld<T, op_ba, F, mapping, composition> hld(e(), id(), tr, info, a);
tifa_libs::graph::hld<T, op_ab, F, mapping, composition> hld1(e(), id(), tr, info, a);
for (u32 i = 0, opt; i < q; ++i) {
std::cin >> opt;
if (opt == 0) {
Expand Down
39 changes: 39 additions & 0 deletions src/test_cpverifier/aizu-grl/grl_5_d.test.cpp
Original file line number Diff line number Diff line change
@@ -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<i64, i32>;
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<T> 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<T, op, F, mapping, composition> 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;
}
40 changes: 40 additions & 0 deletions src/test_cpverifier/aizu-grl/grl_5_e.test.cpp
Original file line number Diff line number Diff line change
@@ -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<i64, i32>;
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<T> 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<T, op, F, mapping, composition> 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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<i64, i32>;
using F = i64;
Expand All @@ -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<T, op, F, mapping, composition> tr({0, 0}, 0, tr_);
tifa_libs::graph::hld<T, op, F, mapping, composition> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<i64, i32>;
using F = i64;
Expand All @@ -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<T, op, F, mapping, composition> tr({0, 0}, 0, tr_);
tifa_libs::graph::hld<T, op, F, mapping, composition> 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) {
Expand Down
Loading

0 comments on commit f78d1a0

Please sign in to comment.