Skip to content

Commit d499bfd

Browse files
committed
add hld
1 parent a0e583d commit d499bfd

File tree

10 files changed

+235
-16
lines changed

10 files changed

+235
-16
lines changed

library/data_structures/dsu/dsu.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
2-
struct dsu {
2+
// NOLINTNEXTLINE(readability-identifier-naming)
3+
struct DSU {
34
vi e;
4-
dsu(int n): e(n, -1) {}
5+
DSU(int n): e(n, -1) {}
56
int size(int x) { return -e[go(x)]; }
67
int go(int x) { return e[x] < 0 ? x : e[x] = go(e[x]); }
78
bool join(int a, int b) {

library/trees/hld.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
//! https://github.com/kth-competitive-programming/kactl/blob/main/content/graph/HLD.h
3+
//! @code
4+
//! vector<basic_string<int>> adj(n);
5+
//! HLD<0> hld(adj);
6+
//! hld.path(u, v, [&](int l, int r) { // [l, r)
7+
//! });
8+
//! auto [l, r] = hld.subtree(v); // [l, r)
9+
//! @endcode
10+
//! @time O(n + q log^2 n)
11+
//! @space O(n)
12+
// NOLINTNEXTLINE(readability-identifier-naming)
13+
template<bool VALS_EDGES> struct HLD {
14+
int n;
15+
vi p, siz, rt, tin;
16+
HLD(auto adj):
17+
n(sz(adj)), p(n), siz(n, 1), rt(n), tin(n) {
18+
auto dfs1 = [&](auto&& self, int v) -> void {
19+
for (int& u : adj[v]) {
20+
adj[u].erase(find(all(adj[u]), v));
21+
p[u] = v;
22+
self(self, u);
23+
siz[v] += siz[u];
24+
if (siz[u] > siz[adj[v][0]]) swap(u, adj[v][0]);
25+
}
26+
};
27+
dfs1(dfs1, 0);
28+
int tim = 0;
29+
auto dfs2 = [&](auto&& self, int v) -> void {
30+
tin[v] = tim++;
31+
for (int u : adj[v]) {
32+
rt[u] = (u == adj[v][0] ? rt[v] : u);
33+
self(self, u);
34+
}
35+
};
36+
dfs2(dfs2, 0);
37+
}
38+
void path(int u, int v, auto f) {
39+
for (;; v = p[rt[v]]) {
40+
if (tin[u] > tin[v]) swap(u, v);
41+
if (rt[u] == rt[v]) break;
42+
f(tin[rt[v]], tin[v] + 1);
43+
}
44+
f(tin[u] + VALS_EDGES, tin[v] + 1);
45+
}
46+
pii subtree(int v) {
47+
return {tin[v] + VALS_EDGES, tin[v] + siz[v]};
48+
}
49+
};

tests/library_checker_aizu_tests/data_structures/dsu.test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ int main() {
55
cin.tie(0)->sync_with_stdio(0);
66
int n, q;
77
cin >> n >> q;
8-
dsu uf(n);
8+
DSU dsu(n);
99
while (q--) {
1010
int type, u, v;
1111
cin >> type >> u >> v;
12-
if (type == 0) uf.join(u, v);
13-
else cout << (uf.go(u) == uf.go(v)) << '\n';
12+
if (type == 0) dsu.join(u, v);
13+
else cout << (dsu.go(u) == dsu.go(v)) << '\n';
1414
}
1515
return 0;
1616
}

tests/library_checker_aizu_tests/graphs/bcc_callback_lib_checker_two_cc.test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int main() {
1414
adj[u].push_back(v);
1515
adj[v].push_back(u);
1616
}
17-
dsu uf(n);
17+
DSU dsu(n);
1818
vector<bool> seen(n);
1919
bcc_callback(adj, [&](const vi& nodes) {
2020
int count_edges = 0;
@@ -28,10 +28,10 @@ int main() {
2828
// nodes[0] <=> nodes[1] is a bridge
2929
return;
3030
}
31-
for (int v : nodes) uf.join(v, nodes[0]);
31+
for (int v : nodes) dsu.join(v, nodes[0]);
3232
});
3333
vector<vi> two_edge_ccs(n);
34-
rep(i, 0, n) two_edge_ccs[uf.go(i)].push_back(i);
34+
rep(i, 0, n) two_edge_ccs[dsu.go(i)].push_back(i);
3535
int cnt_ccs = 0;
3636
rep(i, 0, n) cnt_ccs += (!empty(two_edge_ccs[i]));
3737
cout << cnt_ccs << '\n';

tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@ int main() {
2020
iota(all(order), 0);
2121
ranges::sort(all(order), {},
2222
[&](int i) { return joins[i]; });
23-
dsu uf(n);
23+
DSU dsu(n);
2424
mint sum = 0;
2525
for (int t = 0, it = 0; t < m; t++) {
2626
while (it < m && joins[order[it]] <= t) {
2727
auto [u, v] = eds[order[it]];
28-
u = uf.go(u);
29-
v = uf.go(v);
30-
if (uf.e[u] > uf.e[v]) swap(u, v);
28+
u = dsu.go(u);
29+
v = dsu.go(v);
30+
if (dsu.e[u] > dsu.e[v]) swap(u, v);
3131
if (u != v) {
3232
sum = sum + xs[u] * xs[v];
3333
xs[u] = xs[u] + xs[v];
3434
xs[v] = xs[u];
3535
}
36-
uf.join(u, v);
36+
dsu.join(u, v);
3737
it++;
3838
}
3939
cout << sum.x << '\n';

tests/library_checker_aizu_tests/handmade_tests/dsu.test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ int main() {
77
cin.tie(0)->sync_with_stdio(0);
88
for (int n = 0; n <= 100; n++) {
99
vector<vector<int>> adj(n);
10-
dsu uf(n);
10+
DSU dsu(n);
1111
for (int q = 0; q < n; q++) {
1212
int u = rnd(0, n - 1);
1313
int v = rnd(0, n - 1);
14-
bool joined = uf.join(u, v);
14+
bool joined = dsu.join(u, v);
1515
{
1616
vector<bool> vis(n);
1717
auto dfs = [&](auto&& self, int v) -> void {
@@ -42,7 +42,7 @@ int main() {
4242
};
4343
vis[i] = 1;
4444
dfs(dfs, i);
45-
assert(cnt_nodes == uf.size(i));
45+
assert(cnt_nodes == dsu.size(i));
4646
}
4747
}
4848
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#define PROBLEM \
2+
"https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_D"
3+
#include "../template.hpp"
4+
#include "../../../library/trees/hld.hpp"
5+
#include "../../../library/data_structures/bit.hpp"
6+
int main() {
7+
cin.tie(0)->sync_with_stdio(0);
8+
int n;
9+
cin >> n;
10+
vector<vector<int>> adj(n);
11+
for (int i = 0; i < n; i++) {
12+
int k;
13+
cin >> k;
14+
for (int j = 0; j < k; j++) {
15+
int v;
16+
cin >> v;
17+
assert(v != 0);
18+
adj[i].push_back(v);
19+
adj[v].push_back(i);
20+
}
21+
}
22+
HLD<1> hld(adj);
23+
BIT bit(n);
24+
int q;
25+
cin >> q;
26+
while (q--) {
27+
int type;
28+
cin >> type;
29+
if (type == 0) {
30+
int v, x;
31+
cin >> v >> x;
32+
assert(v != 0);
33+
bit.update(hld.tin[v], x);
34+
} else {
35+
assert(type == 1);
36+
int v;
37+
cin >> v;
38+
ll sum = 0;
39+
hld.path(0, v,
40+
[&](int l, int r) { sum += bit.query(l, r); });
41+
cout << sum << '\n';
42+
}
43+
}
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#define PROBLEM \
2+
"https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_E"
3+
#include "../template.hpp"
4+
#include "../../../library/trees/hld.hpp"
5+
#include "../../../library/data_structures/lazy_seg_tree.hpp"
6+
int main() {
7+
cin.tie(0)->sync_with_stdio(0);
8+
int n;
9+
cin >> n;
10+
vector<vector<int>> adj(n);
11+
for (int i = 0; i < n; i++) {
12+
int k;
13+
cin >> k;
14+
for (int j = 0; j < k; j++) {
15+
int v;
16+
cin >> v;
17+
assert(v != 0);
18+
adj[i].push_back(v);
19+
adj[v].push_back(i);
20+
}
21+
}
22+
HLD<1> hld(adj);
23+
seg_tree st(n);
24+
int q;
25+
cin >> q;
26+
while (q--) {
27+
int type;
28+
cin >> type;
29+
if (type == 0) {
30+
int v, x;
31+
cin >> v >> x;
32+
assert(v != 0);
33+
hld.path(0, v,
34+
[&](int l, int r) { st.update(l, r, x); });
35+
} else {
36+
assert(type == 1);
37+
int v;
38+
cin >> v;
39+
ll sum = 0;
40+
hld.path(0, v,
41+
[&](int l, int r) { sum += st.query(l, r); });
42+
cout << sum << '\n';
43+
}
44+
}
45+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#define PROBLEM \
2+
"https://judge.yosupo.jp/problem/vertex_add_path_sum"
3+
#include "../template.hpp"
4+
#include "../../../library/trees/hld.hpp"
5+
#include "../../../library/data_structures/bit.hpp"
6+
int main() {
7+
cin.tie(0)->sync_with_stdio(0);
8+
int n, q;
9+
cin >> n >> q;
10+
vector<int> a(n);
11+
for (int i = 0; i < n; i++) cin >> a[i];
12+
vector<vector<int>> adj(n);
13+
for (int i = 0; i < n - 1; i++) {
14+
int u, v;
15+
cin >> u >> v;
16+
adj[u].push_back(v);
17+
adj[v].push_back(u);
18+
}
19+
HLD<0> hld(adj);
20+
BIT bit(n);
21+
for (int i = 0; i < n; i++) bit.update(hld.tin[i], a[i]);
22+
while (q--) {
23+
int type;
24+
cin >> type;
25+
if (type == 0) {
26+
int v, x;
27+
cin >> v >> x;
28+
bit.update(hld.tin[v], x);
29+
} else {
30+
int u, v;
31+
cin >> u >> v;
32+
ll sum = 0;
33+
hld.path(u, v,
34+
[&](int l, int r) { sum += bit.query(l, r); });
35+
cout << sum << '\n';
36+
}
37+
}
38+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#define PROBLEM \
2+
"https://judge.yosupo.jp/problem/vertex_add_subtree_sum"
3+
#include "../template.hpp"
4+
#include "../../../library/trees/hld.hpp"
5+
#include "../../../library/data_structures/bit.hpp"
6+
int main() {
7+
cin.tie(0)->sync_with_stdio(0);
8+
int n, q;
9+
cin >> n >> q;
10+
vector<ll> a(n);
11+
for (int i = 0; i < n; i++) cin >> a[i];
12+
vector<vector<int>> adj(n);
13+
for (int i = 1; i < n; i++) {
14+
int par;
15+
cin >> par;
16+
adj[par].push_back(i);
17+
adj[i].push_back(par);
18+
}
19+
HLD<0> hld_nodes(adj);
20+
HLD<1> hld_edges(adj);
21+
BIT bit(n);
22+
for (int i = 0; i < n; i++)
23+
bit.update(hld_nodes.tin[i], a[i]);
24+
while (q--) {
25+
int type;
26+
cin >> type;
27+
if (type == 0) {
28+
int v, x;
29+
cin >> v >> x;
30+
bit.update(hld_nodes.tin[v], x);
31+
a[v] += x;
32+
} else {
33+
int v;
34+
cin >> v;
35+
auto [l, r] = hld_nodes.subtree(v);
36+
ll res = bit.query(l, r);
37+
auto [l_edges, r_edges] = hld_edges.subtree(v);
38+
assert(res == bit.query(l_edges, r_edges) + a[v]);
39+
cout << res << '\n';
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)