TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
heavy_light_decomposition.cpp
Go to the documentation of this file.
1
44#include <algorithm>
45#include <cassert>
46#include <cmath>
47#include <cstring>
48#include <iostream>
49#include <list>
50#include <numeric>
51#include <string>
52#include <vector>
53
58namespace range_queries {
78template <typename X> class Tree {
79 //
80
81private:
82 std::vector<std::list<int>>
84 const int t_nodes,
86 std::vector<std::vector<int>>
88 std::vector<int> t_depth,
90
91 int t_root;
92 std::vector<X> t_val;
93 template <typename T> friend class HLD;
94
101 void dfs_size(int u, int p = -1) {
102 for (const int &v : t_adj[u]) {
103 if (v ^ p) {
104 dfs_size(v, u);
105 t_size[u] += t_size[v];
106 }
107 }
108 }
109
116 void dfs_lca(int u, int p = -1) {
117 t_par[u][0] = p;
118 if (p != -1) {
119 t_depth[u] = 1 + t_depth[p];
120 }
121 for (int k = 1; k < t_maxlift; k++) {
122 if (t_par[u][k - 1] != -1) {
123 t_par[u][k] = t_par[t_par[u][k - 1]][k - 1];
124 }
125 }
126
127 for (const int &v : t_adj[u]) {
128 if (v ^ p) {
129 dfs_lca(v, u);
130 }
131 }
132 }
133
134public:
140 explicit Tree(int nodes)
141 : t_nodes(nodes), t_maxlift(static_cast<int>(floor(log2(nodes))) + 1) {
142 /* Initialize and resize all the vectors */
143 t_root = 0; /* Default */
144 t_adj.resize(t_nodes);
145 t_par.assign(t_nodes, std::vector<int>(t_maxlift, -1));
146 t_depth.assign(t_nodes, 0);
147 t_size.assign(t_nodes, 1);
148 t_val.resize(t_nodes);
149 }
150
157 void add_edge(const int u, const int v) {
158 t_adj[u].push_back(v);
159 t_adj[v].push_back(u);
160 }
161
167 void change_root(int new_root) { t_root = new_root; }
168
175 void set_node_val(const std::vector<X> &node_val) {
176 assert(static_cast<int>(node_val.size()) == t_nodes);
177 t_val = node_val;
178 }
179
186 void init() {
187 assert(t_nodes > 0);
190 }
191
200 void lift(int *const p, int dist) {
201 for (int k = 0; k < t_maxlift; k++) {
202 if (*p == -1) {
203 return;
204 }
205 if (dist & 1) {
206 *p = t_par[*p][k];
207 }
208 dist >>= 1;
209 }
210 }
211
218 int kth_ancestor(int p, const int &dist) {
219 lift(&p, dist);
220 return p;
221 }
222
229 int lca(int a, int b) {
230 assert(a >= 0 and b >= 0 and a < t_nodes and b < t_nodes);
231 if (t_depth[a] > t_depth[b]) {
232 lift(&a, t_depth[a] - t_depth[b]);
233 }
234 if (t_depth[b] > t_depth[a]) {
235 lift(&b, t_depth[b] - t_depth[a]);
236 }
237 if (a == b) {
238 return a;
239 }
240 for (int k = t_maxlift - 1; k >= 0; k--) {
241 if (t_par[a][k] != t_par[b][k]) {
242 a = t_par[a][k];
243 b = t_par[b][k];
244 }
245 }
246 return t_par[a][0];
247 }
248};
249
254template <typename X> class SG {
255private:
262 std::vector<X> s_tree;
263 int s_size;
264 X sret_init = 0;
265 template <typename T> friend class HLD;
266
274 X combine(X lhs, X rhs) { return lhs + rhs; }
275
282 explicit SG(int size) {
283 s_size = size;
284 s_tree.assign(2 * s_size, 0ll);
285 }
286
293 void update(int p, X v) {
294 for (p += s_size; p > 0; p >>= 1) {
295 s_tree[p] += v;
296 }
297 }
298
305 X query(int l, int r) {
306 X lhs = sret_init, rhs = sret_init;
307 for (l += s_size, r += s_size + 1; l < r; l >>= 1, r >>= 1) {
308 if (l & 1) {
309 lhs = combine(lhs, s_tree[l++]);
310 }
311 if (r & 1) {
312 rhs = combine(s_tree[--r], rhs);
313 }
314 }
315 return combine(lhs, rhs);
316 }
317
329 void set_sret_init(X new_sret_init) { sret_init = new_sret_init; }
330};
331
336template <typename X> class HLD : public Tree<X>, public SG<X> {
337private:
338 int label;
339 std::vector<int> h_label,
342
350 void dfs_hc(int u, int p = -1) {
351 int hc_size = -1, hc_id = -1;
352 for (const int &v : Tree<X>::t_adj[u]) {
353 if (v ^ p) {
354 dfs_hc(v, u);
355 if (Tree<X>::t_size[v] > hc_size) {
356 hc_size = Tree<X>::t_size[v];
357 hc_id = v;
358 }
359 }
360 }
361 h_heavychlid[u] = hc_id;
362 }
363
371 void dfs_par(int u, int p = -1) {
372 if (h_heavychlid[u] != -1) {
374 dfs_par(h_heavychlid[u], u);
375 }
376 for (const int &v : Tree<X>::t_adj[u]) {
377 if (v ^ p and v ^ h_heavychlid[u]) {
378 dfs_par(v, u);
379 }
380 }
381 }
382
390 void dfs_labels(int u, int p = -1) {
391 h_label[u] = label++;
392 if (h_heavychlid[u] != -1) {
394 }
395 for (const int &v : Tree<X>::t_adj[u]) {
396 if (v ^ p and v ^ h_heavychlid[u]) {
397 dfs_labels(v, u);
398 }
399 }
400 }
401
409 X chain_query(int a, int b) {
410 X ret = SG<X>::sret_init;
412 std::swap(a, b);
413 }
414 while (Tree<X>::t_depth[a] >= Tree<X>::t_depth[b]) {
415 int l = h_label[h_parent[a]];
416 int r = h_label[a];
419 }
420 ret = SG<X>::combine(ret, SG<X>::query(l, r));
421 a = Tree<X>::t_par[h_parent[a]][0];
422 if (a == -1) {
423 break;
424 }
425 }
426 return ret;
427 }
428
429public:
435 explicit HLD<X>(int nodes) : Tree<X>(nodes), SG<X>(nodes) {
436 /* Initialization and resize vectors */
437 label = 0;
438 h_label.assign(Tree<X>::t_nodes, -1);
439 h_heavychlid.assign(Tree<X>::t_nodes, -1);
441 iota(h_parent.begin(), h_parent.end(), 0);
442 }
443
450 void init() {
452
453 // Fill the heavy child, greatest parent, and labels
454 label = 0;
458
459 // Segment Tree Initialization
460 for (int i = 0; i < Tree<X>::t_nodes; i++) {
462 }
463 for (int i = Tree<X>::t_nodes - 1; i > 0; i--) {
464 SG<X>::s_tree[i] =
465 SG<X>::combine(SG<X>::s_tree[i << 1], SG<X>::s_tree[i << 1 | 1]);
466 }
467 }
468
475 void update(int node, X val) {
476 X diff = val - Tree<X>::t_val[node];
477 SG<X>::update(h_label[node], diff);
478 Tree<X>::t_val[node] = val;
479 }
480
489 X query(int a, int b) {
490 int lc = Tree<X>::lca(a, b);
491 X ret = SG<X>::sret_init;
492 assert(lc != -1);
493 ret += chain_query(a, lc);
494 ret += chain_query(b, lc);
495 return ret - Tree<X>::t_val[lc];
496 }
497};
498} // namespace heavy_light_decomposition
499} // namespace range_queries
500
505static void test_1() {
506 std::cout << "Test 1:\n";
507
508 // Test details
509 int n = 5;
510 std::vector<int64_t> node_values = {4, 2, 5, 2, 1};
511 std::vector<std::vector<int>> edges = {{1, 2}, {1, 3}, {3, 4}, {3, 5}};
512 std::vector<std::vector<int>> queries = {
513 {2, 1, 4},
514 {1, 3, 2},
515 {2, 1, 4},
516 };
517 std::vector<int> expected_result = {11, 8};
518 std::vector<int> code_result;
519
521 hld.set_node_val(node_values);
522 for (int i = 0; i < n - 1; i++) {
523 int u = edges[i][0], v = edges[i][1];
524 hld.add_edge(u - 1, v - 1);
525 }
526 hld.init();
527 for (const auto &q : queries) {
528 int type = q[0];
529 if (type == 1) {
530 int p = q[1], x = q[2];
531 hld.update(p - 1, x);
532 } else if (type == 2) {
533 int a = q[1], b = q[2];
534 code_result.push_back(hld.query(a - 1, b - 1));
535 } else {
536 continue;
537 }
538 }
539 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
540 assert(expected_result[i] == code_result[i]);
541 }
542 std::cout << "\nTest 1 passed!\n";
543}
544
549static void test_2() {
550 std::cout << "Test 2:\n";
551
552 // Test details (Bamboo)
553 int n = 10;
554 std::vector<int64_t> node_values = {1, 8, 6, 8, 6, 2, 9, 2, 3, 2};
555 std::vector<std::vector<int>> edges = {
556 {10, 5}, {6, 2}, {10, 7}, {5, 2}, {3, 9}, {8, 3}, {1, 4}, {6, 4}, {8, 7}};
557 std::vector<std::vector<int>> queries = {
558 {2, 1, 10}, {2, 1, 6}, {1, 3, 4}, {2, 1, 9}, {1, 5, 3},
559 {1, 7, 8}, {2, 1, 4}, {2, 1, 8}, {1, 1, 4}, {1, 2, 7}};
560 std::vector<int> expected_result = {27, 11, 45, 9, 34};
561 std::vector<int> code_result;
562
564 hld.set_node_val(node_values);
565 for (int i = 0; i < n - 1; i++) {
566 int u = edges[i][0], v = edges[i][1];
567 hld.add_edge(u - 1, v - 1);
568 }
569 hld.init();
570 for (const auto &q : queries) {
571 int type = q[0];
572 if (type == 1) {
573 int p = q[1], x = q[2];
574 hld.update(p - 1, x);
575 } else if (type == 2) {
576 int a = q[1], b = q[2];
577 code_result.push_back(hld.query(a - 1, b - 1));
578 } else {
579 continue;
580 }
581 }
582 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
583 assert(expected_result[i] == code_result[i]);
584 }
585 std::cout << "\nTest2 passed!\n";
586}
587
592static void test_3() {
593 std::cout << "Test 3:\n";
594
595 // Test details
596 int n = 8;
597 std::vector<int64_t> node_values = {1, 8, 6, 8, 6, 2, 9, 2};
598 std::vector<std::vector<int>> edges = {{1, 2}, {2, 3}, {3, 4}, {1, 5},
599 {6, 3}, {7, 5}, {8, 7}};
600 std::vector<std::vector<int>> queries = {
601 {2, 6, 8}, {2, 3, 6}, {1, 3, 4}, {2, 7, 1}, {1, 5, 3},
602 {1, 7, 8}, {2, 6, 4}, {2, 7, 8}, {1, 1, 4}, {1, 2, 7}};
603 std::vector<int> expected_result = {34, 8, 16, 14, 10};
604 std::vector<int> code_result;
605
607 hld.set_node_val(node_values);
608 for (int i = 0; i < n - 1; i++) {
609 int u = edges[i][0], v = edges[i][1];
610 hld.add_edge(u - 1, v - 1);
611 }
612 hld.init();
613 for (const auto &q : queries) {
614 int type = q[0];
615 if (type == 1) {
616 int p = q[1], x = q[2];
617 hld.update(p - 1, x);
618 } else if (type == 2) {
619 int a = q[1], b = q[2];
620 code_result.push_back(hld.query(a - 1, b - 1));
621 } else {
622 continue;
623 }
624 }
625 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
626 assert(expected_result[i] == code_result[i]);
627 }
628 std::cout << "\nTest3 passed!\n";
629}
630
634int main() {
635 test_1();
636 test_2();
637 test_3();
638 return 0;
639}
struct node { int data; int height; struct node *left; struct node *right;} node
for std::queue
Definition avltree.cpp:13
void dfs_labels(int u, int p=-1)
Utility function to lable the nodes so that heavy chains have a contigous lable.
std::vector< int > h_parent
stores the top of the heavy chain from a node
void dfs_par(int u, int p=-1)
Utility function to assign highest parent that can be reached though heavy chains.
X query(int a, int b)
This function returns the sum of node values in the simple path from from node_1 to node_2.
int label
utility member to assign labels in dfs_labels()
X chain_query(int a, int b)
Utility function to break down a path query into two chain queries.
std::vector< int > h_heavychlid
stores the heavy child of a node
void update(int node, X val)
This function updates the value at node with val.
std::vector< int > h_label
stores the label of a node
void init()
This function must be called after the tree adjacency list and node values are populated The function...
void dfs_hc(int u, int p=-1)
Utility function to assign heavy child to each node (-1 for a leaf node)
X query(int l, int r)
Make a range query from node label l to node label r.
void update(int p, X v)
Update the value at a node.
X combine(X lhs, X rhs)
Function that specifies the type of operation involved when segments are combined.
int s_size
number of leaves in the segment tree
void set_sret_init(X new_sret_init)
Set the initialization for the query data type, based on requirement.
SG(int size)
Class parameterized constructor. Resizes the and initilizes the data members.
std::vector< X > s_tree
Everything here is private, and can only be accessed through the methods, in the derived class (HLD)
A Basic Tree, which supports binary lifting.
void set_node_val(const std::vector< X > &node_val)
Set the values for all the nodes.
std::vector< int > t_depth
a vector to store the depth of a node,
std::vector< std::vector< int > > t_par
a matrix to store every node's 2^kth parent
void add_edge(const int u, const int v)
Adds an undirected edge from node u to node v in the tree.
Tree(int nodes)
Class parameterized constructor, resizes the and initializes the data members.
int kth_ancestor(int p, const int &dist)
The function returns the kth ancestor of a node.
void dfs_size(int u, int p=-1)
Utility function to compute sub-tree sizes.
std::vector< std::list< int > > t_adj
an adjacency list to stores the tree edges
const int t_maxlift
maximum possible height of the tree
void change_root(int new_root)
Set the root for the tree.
void lift(int *const p, int dist)
The function lifts a node, k units up the tree. The lifting is done in place, and the result is store...
void init()
This function must be called after the tree adjacency list and node values are populated The function...
std::vector< int > t_size
a vector to store the subtree size rooted at node
int lca(int a, int b)
The function returns the least common ancestor of two nodes.
void dfs_lca(int u, int p=-1)
Utility function to populate the t_par vector.
static void test_1()
static void test_2()
static void test_3()
Heavy light decomposition algorithm.
for std::vector