-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlca-sparse-table.cpp
67 lines (61 loc) · 1.88 KB
/
lca-sparse-table.cpp
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
65
66
67
typedef vector<vl> vl2d;
#define all(a) a.begin(), a.end()
#define len(x) (int)x.size()
template <typename T>
struct SparseTable {
vector<T> v;
ll n;
static const ll b = 30;
vl mask, t;
ll op(ll x, ll y) { return v[x] < v[y] ? x : y; }
ll msb(ll x) { return __builtin_clz(1) - __builtin_clz(x); }
SparseTable() {}
SparseTable(const vector<T>& v_) : v(v_), n(v.size()), mask(n), t(n) {
for (ll i = 0, at = 0; i < n; mask[i++] = at |= 1) {
at = (at << 1) & ((1 << b) - 1);
while (at and op(i, i - msb(at & -at)) == i) at ^= at & -at;
}
for (ll i = 0; i < n / b; i++)
t[i] = b * i + b - 1 - msb(mask[b * i + b - 1]);
for (ll j = 1; (1 << j) <= n / b; j++)
for (ll i = 0; i + (1 << j) <= n / b; i++)
t[n / b * j + i] =
op(t[n / b * (j - 1) + i], t[n / b * (j - 1) + i + (1 << (j - 1))]);
}
ll small(ll r, ll sz = b) { return r - msb(mask[r] & ((1 << sz) - 1)); }
T query(ll l, ll r) {
if (r - l + 1 <= b) return small(r, r - l + 1);
ll ans = op(small(l + b - 1), small(r));
ll x = l / b + 1, y = r / b - 1;
if (x <= y) {
ll j = msb(y - x + 1);
ans = op(ans, op(t[n / b * j + x], t[n / b * j + y - (1 << j) + 1]));
}
return ans;
}
};
struct LCA {
SparseTable<ll> st;
ll n;
vl v, pos, dep;
LCA(const vl2d& g, ll root) : n(len(g)), pos(n) {
dfs(root, 0, -1, g);
st = SparseTable<ll>(vector<ll>(all(dep)));
}
void dfs(ll i, ll d, ll p, const vl2d& g) {
v.emplace_back(len(dep)) = i, pos[i] = len(dep), dep.emplace_back(d);
for (auto j : g[i])
if (j != p) {
dfs(j, d + 1, i, g);
v.emplace_back(len(dep)) = i, dep.emplace_back(d);
}
}
ll lca(ll a, ll b) {
ll l = min(pos[a], pos[b]);
ll r = max(pos[a], pos[b]);
return v[st.query(l, r)];
}
ll dist(ll a, ll b) {
return dep[pos[a]] + dep[pos[b]] - 2 * dep[pos[lca(a, b)]];
}
};