Skip to content

Commit f5011ab

Browse files
committed
Add HLD and LCA
1 parent cdb9aed commit f5011ab

File tree

7 files changed

+122
-13
lines changed

7 files changed

+122
-13
lines changed

cp-algo/graph/base.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,17 @@ namespace cp_algo::graph {
2323
}
2424
return gt;
2525
}
26-
void add_edge(node_index u, edge_t e) {
26+
edge_index add_edge(node_index u, edge_t e) {
2727
edge_index idx = (edge_index)size(E);
2828
E.push_back(e);
2929
adj.push(u, idx);
3030
if constexpr (mode == undirected) {
3131
adj.push(e.traverse(u), idx);
3232
}
33+
return idx;
3334
}
34-
void add_edge(node_index u, auto... Args) {
35-
add_edge(u, edge_t(u, Args...));
35+
edge_index add_edge(node_index u, auto... Args) {
36+
return add_edge(u, edge_t(u, Args...));
3637
}
3738
void read_edges(node_index m) {
3839
adj.reserve(mode == undirected ? 2 * m : m);

cp-algo/graph/ascending_dfs.hpp renamed to cp-algo/tree/ascending_dfs.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#ifndef CP_ALGO_GRAPH_ASCENDING_DFS_HPP
2-
#define CP_ALGO_GRAPH_ASCENDING_DFS_HPP
1+
#ifndef CP_ALGO_TREE_ASCENDING_DFS_HPP
2+
#define CP_ALGO_TREE_ASCENDING_DFS_HPP
33

4-
#include "base.hpp"
4+
#include "../graph/base.hpp"
55
#include <cassert>
66
#include <vector>
77
#include <ranges>
@@ -65,4 +65,4 @@ namespace cp_algo::graph {
6565
}, callback, root);
6666
}
6767
}
68-
#endif // CP_ALGO_GRAPH_ASCENDING_DFS_HPP
68+
#endif // CP_ALGO_TREE_ASCENDING_DFS_HPP

cp-algo/graph/tree_diameter.hpp renamed to cp-algo/tree/diameter.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#ifndef CP_ALGO_GRAPH_TREE_DIAMETER_HPP
2-
#define CP_ALGO_GRAPH_TREE_DIAMETER_HPP
1+
#ifndef CP_ALGO_TREE_DIAMETER_HPP
2+
#define CP_ALGO_TREE_DIAMETER_HPP
33
#include "ascending_dfs.hpp"
4-
#include "base.hpp"
4+
#include "../graph/base.hpp"
55
#include <tuple>
66
#include <string>
77
#include <algorithm>
@@ -59,4 +59,4 @@ namespace cp_algo::graph {
5959
}
6060
}
6161
}
62-
#endif // CP_ALGO_GRAPH_TREE_DIAMETER_HPP
62+
#endif // CP_ALGO_TREE_DIAMETER_HPP

cp-algo/tree/hld.hpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#ifndef CP_ALGO_TREE_HLD_HPP
2+
#define CP_ALGO_TREE_HLD_HPP
3+
#include "ascending_dfs.hpp"
4+
#include "../graph/base.hpp"
5+
#include "../util/big_alloc.hpp"
6+
#include <vector>
7+
#include <ranges>
8+
9+
namespace cp_algo::graph {
10+
struct heavy_light {
11+
big_vector<node_index> size, in, up, par;
12+
13+
template<undirected_graph_type graph>
14+
heavy_light(graph const& g, node_index root = 0, std::vector<edge_index> const* parents_ptr = nullptr):
15+
size(g.n(), 1), in(g.n()), up(g.n()), par(g.n()) {
16+
big_vector<node_index> topsort;
17+
topsort.reserve(g.n());
18+
auto push_size = [&](node_index v, edge_index e) {
19+
topsort.push_back(v);
20+
if (v != root) {
21+
auto p = g.edge(e).traverse(v);
22+
size[p] += size[v];
23+
par[v] = p;
24+
}
25+
};
26+
if (parents_ptr) {
27+
parent_dfs(g, *parents_ptr, push_size);
28+
} else {
29+
xor_dfs(g, push_size, root);
30+
}
31+
par[root] = up[root] = root;
32+
for(auto v: topsort | std::views::reverse) {
33+
node_index big = -1;
34+
for(auto e: g.outgoing(v)) {
35+
auto u = g.edge(e).traverse(v);
36+
if (size[u] > size[v]) continue;
37+
if (big == -1 || size[u] > size[big]) {
38+
big = u;
39+
}
40+
}
41+
int t = in[v] + (big == -1 ? 0 : size[big]);
42+
for(auto e: g.outgoing(v)) {
43+
auto u = g.edge(e).traverse(v);
44+
if (size[u] > size[v]) continue;
45+
if (u == big) {
46+
in[u] = in[v] + 1;
47+
up[u] = up[v];
48+
} else {
49+
in[u] = t + 1;
50+
t += size[u];
51+
up[u] = u;
52+
}
53+
}
54+
}
55+
}
56+
node_index lca(node_index a, node_index b) {
57+
while (up[a] != up[b]) {
58+
if (in[up[a]] < in[up[b]]) {
59+
b = par[up[b]];
60+
} else {
61+
a = par[up[a]];
62+
}
63+
}
64+
return in[a] < in[b] ? a : b;
65+
}
66+
};
67+
}
68+
#endif // CP_ALGO_TREE_HLD_HPP

verify/graph/minimum_diameter_spanning_tree.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <iostream>
55
#include "blazingio/blazingio.min.hpp"
66
#include "cp-algo/graph/shortest_path.hpp"
7-
#include "cp-algo/graph/tree_diameter.hpp"
7+
#include "cp-algo/tree/diameter.hpp"
88
#include <bits/stdc++.h>
99

1010
using namespace std;

verify/graph/tree_diameter.test.cpp renamed to verify/tree/diameter.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#pragma GCC optimize("Ofast,unroll-loops")
44
#include <iostream>
55
#include "blazingio/blazingio.min.hpp"
6-
#include "cp-algo/graph/tree_diameter.hpp"
6+
#include "cp-algo/tree/diameter.hpp"
77
#include <bits/stdc++.h>
88

99
using namespace std;

verify/tree/lca.test.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// @brief Lowest Common Ancestor
2+
#define PROBLEM "https://judge.yosupo.jp/problem/lca"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include <iostream>
5+
#include "blazingio/blazingio.min.hpp"
6+
#include "cp-algo/tree/hld.hpp"
7+
#include <bits/stdc++.h>
8+
9+
using namespace std;
10+
using namespace cp_algo::graph;
11+
12+
void solve() {
13+
int n, q;
14+
cin >> n >> q;
15+
graph g(n);
16+
vector<edge_index> p(n);
17+
p[0] = -1;
18+
for(int i = 1; i < n; i++) {
19+
node_index v;
20+
cin >> v;
21+
p[i] = g.add_edge(v, i);
22+
}
23+
heavy_light hld(g, 0, &p);
24+
for(int i = 0; i < q; i++) {
25+
node_index u, v;
26+
cin >> u >> v;
27+
cout << hld.lca(u, v) << '\n';
28+
}
29+
}
30+
31+
signed main() {
32+
//freopen("input.txt", "r", stdin);
33+
ios::sync_with_stdio(0);
34+
cin.tie(0);
35+
int t = 1;
36+
//cin >> t;
37+
while(t--) {
38+
solve();
39+
}
40+
}

0 commit comments

Comments
 (0)