-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathlca_rmq.hpp
64 lines (56 loc) · 1.69 KB
/
lca_rmq.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#pragma once
#include "../sparse_table/rmq_sparse_table.hpp"
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>
struct TreeLCA {
const int N;
std::vector<std::vector<int>> to;
int root;
TreeLCA(int V = 0) : N(V), to(V), root(-1) {}
void add_edge(int u, int v) {
assert(0 <= u and u < N);
assert(0 <= v and v < N);
assert(u != v);
to[u].push_back(v);
to[v].push_back(u);
}
using P = std::pair<int, int>;
std::vector<int> subtree_begin;
std::vector<P> vis_order;
std::vector<int> depth;
void _build_dfs(int now, int prv, int dnow) {
subtree_begin[now] = vis_order.size();
vis_order.emplace_back(dnow, now);
depth[now] = dnow;
for (auto &&nxt : to[now]) {
if (nxt != prv) {
_build_dfs(nxt, now, dnow + 1);
vis_order.emplace_back(dnow, now);
}
}
}
StaticRMQ<P> rmq;
void build(int root_) {
assert(root_ >= 0 and root_ < N);
if (root == root_) return;
root = root_;
subtree_begin.assign(N, 0);
vis_order.clear();
vis_order.reserve(N * 2);
depth.assign(N, 0);
_build_dfs(root, -1, 0);
rmq = {vis_order, P{N, -1}};
}
bool built() const noexcept { return root >= 0; }
int lca(int u, int v) const {
assert(0 <= u and u < N);
assert(0 <= v and v < N);
assert(built());
int a = subtree_begin[u], b = subtree_begin[v];
if (a > b) std::swap(a, b);
return rmq.get(a, b + 1).second;
};
int path_length(int u, int v) const { return depth[u] + depth[v] - depth[lca(u, v)] * 2; }
};