forked from bicsi/code_snippets
-
Notifications
You must be signed in to change notification settings - Fork 0
/
heavy_path.cpp
81 lines (63 loc) · 1.93 KB
/
heavy_path.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class HeavyLight {
struct Node {
int jump, subsize, depth, lin, parent;
vector<int> leg;
};
vector<Node> T;
bool processed;
public:
HeavyLight(int n) : T(n) {}
void AddEdge(int a, int b) {
T[a].leg.push_back(b);
T[b].leg.push_back(a);
}
void Preprocess() {
dfs_sub(0, -1);
dfs_jump(0, 0);
processed = true;
}
// Gets the position in the HL linearization
int GetPosition(int node) {
assert(processed);
return T[node].lin;
}
// Gets an array of ranges of form [li...ri)
// that correspond to the ranges you would need
// to query in the underlying structure
vector<pair<int, int>> GetPathRanges(int a, int b) {
assert(processed);
vector<pair<int, int>> ret;
while (T[a].jump != T[b].jump) {
if (T[T[a].jump].depth < T[T[b].jump].depth)
swap(a, b);
ret.emplace_back(T[T[a].jump].lin, T[a].lin + 1);
a = T[T[a].jump].parent;
}
if (T[a].depth < T[b].depth) swap(a, b);
ret.emplace_back(T[b].lin, T[a].lin + 1);
return ret;
}
private:
int dfs_sub(int x, int par) {
auto &node = T[x];
node.subsize = 1;
node.parent = par;
if (par != -1) {
node.leg.erase(find(node.leg.begin(), node.leg.end(), par));
node.depth = 1 + T[par].depth;
}
for (auto vec : node.leg)
node.subsize += dfs_sub(vec, x);
return node.subsize;
}
int timer = 0;
void dfs_jump(int x, int jump) {
auto &node = T[x];
node.jump = jump;
node.lin = timer++;
iter_swap(node.leg.begin(), max_element(node.leg.begin(), node.leg.end(),
[&](int a, int b) { return T[a].subsize < T[b].subsize; }));
for (auto vec : node.leg)
dfs_jump(vec, vec == node.leg.front() ? jump : vec);
}
};