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
43
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>
79class Tree {
80 //
81
82 private:
83 std::vector<std::list<int>>
85 const int t_nodes,
87 std::vector<std::vector<int>>
89 std::vector<int> t_depth,
91
92 int t_root;
93 std::vector<X> t_val;
94 template <typename T>
95 friend class HLD;
96
103 void dfs_size(int u, int p = -1) {
104 for (const int &v : t_adj[u]) {
105 if (v ^ p) {
106 dfs_size(v, u);
107 t_size[u] += t_size[v];
108 }
109 }
110 }
111
118 void dfs_lca(int u, int p = -1) {
119 t_par[u][0] = p;
120 if (p != -1) {
121 t_depth[u] = 1 + t_depth[p];
122 }
123 for (int k = 1; k < t_maxlift; k++) {
124 if (t_par[u][k - 1] != -1) {
125 t_par[u][k] = t_par[t_par[u][k - 1]][k - 1];
126 }
127 }
128
129 for (const int &v : t_adj[u]) {
130 if (v ^ p) {
131 dfs_lca(v, u);
132 }
133 }
134 }
135
136 public:
142 explicit Tree(int nodes)
143 : t_nodes(nodes), t_maxlift(static_cast<int>(floor(log2(nodes))) + 1) {
144 /* Initialize and resize all the vectors */
145 t_root = 0; /* Default */
146 t_adj.resize(t_nodes);
147 t_par.assign(t_nodes, std::vector<int>(t_maxlift, -1));
148 t_depth.assign(t_nodes, 0);
149 t_size.assign(t_nodes, 1);
150 t_val.resize(t_nodes);
151 }
152
159 void add_edge(const int u, const int v) {
160 t_adj[u].push_back(v);
161 t_adj[v].push_back(u);
162 }
163
169 void change_root(int new_root) { t_root = new_root; }
170
177 void set_node_val(const std::vector<X> &node_val) {
178 assert(static_cast<int>(node_val.size()) == t_nodes);
179 t_val = node_val;
180 }
181
188 void init() {
189 assert(t_nodes > 0);
192 }
193
202 void lift(int *const p, int dist) {
203 for (int k = 0; k < t_maxlift; k++) {
204 if (*p == -1) {
205 return;
206 }
207 if (dist & 1) {
208 *p = t_par[*p][k];
209 }
210 dist >>= 1;
211 }
212 }
213
220 int kth_ancestor(int p, const int &dist) {
221 lift(&p, dist);
222 return p;
223 }
224
231 int lca(int a, int b) {
232 assert(a >= 0 and b >= 0 and a < t_nodes and b < t_nodes);
233 if (t_depth[a] > t_depth[b]) {
234 lift(&a, t_depth[a] - t_depth[b]);
235 }
236 if (t_depth[b] > t_depth[a]) {
237 lift(&b, t_depth[b] - t_depth[a]);
238 }
239 if (a == b) {
240 return a;
241 }
242 for (int k = t_maxlift - 1; k >= 0; k--) {
243 if (t_par[a][k] != t_par[b][k]) {
244 a = t_par[a][k];
245 b = t_par[b][k];
246 }
247 }
248 return t_par[a][0];
249 }
250};
251
256template <typename X>
257class SG {
258 private:
264
265 std::vector<X> s_tree;
266 int s_size;
267 X sret_init = 0;
268 template <typename T>
269 friend class HLD;
270
278 X combine(X lhs, X rhs) { return lhs + rhs; }
279
286 explicit SG(int size) {
287 s_size = size;
288 s_tree.assign(2 * s_size, 0ll);
289 }
290
297 void update(int p, X v) {
298 for (p += s_size; p > 0; p >>= 1) {
299 s_tree[p] += v;
300 }
301 }
302
309 X query(int l, int r) {
310 X lhs = sret_init, rhs = sret_init;
311 for (l += s_size, r += s_size + 1; l < r; l >>= 1, r >>= 1) {
312 if (l & 1) {
313 lhs = combine(lhs, s_tree[l++]);
314 }
315 if (r & 1) {
316 rhs = combine(s_tree[--r], rhs);
317 }
318 }
319 return combine(lhs, rhs);
320 }
321
334 void set_sret_init(X new_sret_init) { sret_init = new_sret_init; }
335};
336
341template <typename X>
342class HLD : public Tree<X>, public SG<X> {
343 private:
344 int label;
345 std::vector<int> h_label,
348
356 void dfs_hc(int u, int p = -1) {
357 int hc_size = -1, hc_id = -1;
358 for (const int &v : Tree<X>::t_adj[u]) {
359 if (v ^ p) {
360 dfs_hc(v, u);
361 if (Tree<X>::t_size[v] > hc_size) {
362 hc_size = Tree<X>::t_size[v];
363 hc_id = v;
364 }
365 }
366 }
367 h_heavychlid[u] = hc_id;
368 }
369
377 void dfs_par(int u, int p = -1) {
378 if (h_heavychlid[u] != -1) {
380 dfs_par(h_heavychlid[u], u);
381 }
382 for (const int &v : Tree<X>::t_adj[u]) {
383 if (v ^ p and v ^ h_heavychlid[u]) {
384 dfs_par(v, u);
385 }
386 }
387 }
388
396 void dfs_labels(int u, int p = -1) {
397 h_label[u] = label++;
398 if (h_heavychlid[u] != -1) {
400 }
401 for (const int &v : Tree<X>::t_adj[u]) {
402 if (v ^ p and v ^ h_heavychlid[u]) {
403 dfs_labels(v, u);
404 }
405 }
406 }
407
415 X chain_query(int a, int b) {
416 X ret = SG<X>::sret_init;
418 std::swap(a, b);
419 }
420 while (Tree<X>::t_depth[a] >= Tree<X>::t_depth[b]) {
421 int l = h_label[h_parent[a]];
422 int r = h_label[a];
425 }
426 ret = SG<X>::combine(ret, SG<X>::query(l, r));
427 a = Tree<X>::t_par[h_parent[a]][0];
428 if (a == -1) {
429 break;
430 }
431 }
432 return ret;
433 }
434
435 public:
441 explicit HLD(int nodes) : Tree<X>(nodes), SG<X>(nodes) {
442 /* Initialization and resize vectors */
443 label = 0;
444 h_label.assign(Tree<X>::t_nodes, -1);
445 h_heavychlid.assign(Tree<X>::t_nodes, -1);
447 iota(h_parent.begin(), h_parent.end(), 0);
448 }
449
456 void init() {
458
459 // Fill the heavy child, greatest parent, and labels
460 label = 0;
464
465 // Segment Tree Initialization
466 for (int i = 0; i < Tree<X>::t_nodes; i++) {
468 }
469 for (int i = Tree<X>::t_nodes - 1; i > 0; i--) {
471 SG<X>::s_tree[i << 1 | 1]);
472 }
473 }
474
481 void update(int node, X val) {
482 X diff = val - Tree<X>::t_val[node];
483 SG<X>::update(h_label[node], diff);
484 Tree<X>::t_val[node] = val;
485 }
486
495 X query(int a, int b) {
496 int lc = Tree<X>::lca(a, b);
497 X ret = SG<X>::sret_init;
498 assert(lc != -1);
499 ret += chain_query(a, lc);
500 ret += chain_query(b, lc);
501 return ret - Tree<X>::t_val[lc];
502 }
503};
504} // namespace heavy_light_decomposition
505} // namespace range_queries
506
511static void test_1() {
512 std::cout << "Test 1:\n";
513
514 // Test details
515 int n = 5;
516 std::vector<int64_t> node_values = {4, 2, 5, 2, 1};
517 std::vector<std::vector<int>> edges = {{1, 2}, {1, 3}, {3, 4}, {3, 5}};
518 std::vector<std::vector<int>> queries = {
519 {2, 1, 4},
520 {1, 3, 2},
521 {2, 1, 4},
522 };
523 std::vector<int> expected_result = {11, 8};
524 std::vector<int> code_result;
525
527 hld.set_node_val(node_values);
528 for (int i = 0; i < n - 1; i++) {
529 int u = edges[i][0], v = edges[i][1];
530 hld.add_edge(u - 1, v - 1);
531 }
532 hld.init();
533 for (const auto &q : queries) {
534 int type = q[0];
535 if (type == 1) {
536 int p = q[1], x = q[2];
537 hld.update(p - 1, x);
538 } else if (type == 2) {
539 int a = q[1], b = q[2];
540 code_result.push_back(hld.query(a - 1, b - 1));
541 } else {
542 continue;
543 }
544 }
545 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
546 assert(expected_result[i] == code_result[i]);
547 }
548 std::cout << "\nTest 1 passed!\n";
549}
550
555static void test_2() {
556 std::cout << "Test 2:\n";
557
558 // Test details (Bamboo)
559 int n = 10;
560 std::vector<int64_t> node_values = {1, 8, 6, 8, 6, 2, 9, 2, 3, 2};
561 std::vector<std::vector<int>> edges = {{10, 5}, {6, 2}, {10, 7},
562 {5, 2}, {3, 9}, {8, 3},
563 {1, 4}, {6, 4}, {8, 7}};
564 std::vector<std::vector<int>> queries = {
565 {2, 1, 10}, {2, 1, 6}, {1, 3, 4}, {2, 1, 9}, {1, 5, 3},
566 {1, 7, 8}, {2, 1, 4}, {2, 1, 8}, {1, 1, 4}, {1, 2, 7}};
567 std::vector<int> expected_result = {27, 11, 45, 9, 34};
568 std::vector<int> code_result;
569
571 hld.set_node_val(node_values);
572 for (int i = 0; i < n - 1; i++) {
573 int u = edges[i][0], v = edges[i][1];
574 hld.add_edge(u - 1, v - 1);
575 }
576 hld.init();
577 for (const auto &q : queries) {
578 int type = q[0];
579 if (type == 1) {
580 int p = q[1], x = q[2];
581 hld.update(p - 1, x);
582 } else if (type == 2) {
583 int a = q[1], b = q[2];
584 code_result.push_back(hld.query(a - 1, b - 1));
585 } else {
586 continue;
587 }
588 }
589 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
590 assert(expected_result[i] == code_result[i]);
591 }
592 std::cout << "\nTest2 passed!\n";
593}
594
599static void test_3() {
600 std::cout << "Test 3:\n";
601
602 // Test details
603 int n = 8;
604 std::vector<int64_t> node_values = {1, 8, 6, 8, 6, 2, 9, 2};
605 std::vector<std::vector<int>> edges = {{1, 2}, {2, 3}, {3, 4}, {1, 5},
606 {6, 3}, {7, 5}, {8, 7}};
607 std::vector<std::vector<int>> queries = {
608 {2, 6, 8}, {2, 3, 6}, {1, 3, 4}, {2, 7, 1}, {1, 5, 3},
609 {1, 7, 8}, {2, 6, 4}, {2, 7, 8}, {1, 1, 4}, {1, 2, 7}};
610 std::vector<int> expected_result = {34, 8, 16, 14, 10};
611 std::vector<int> code_result;
612
614 hld.set_node_val(node_values);
615 for (int i = 0; i < n - 1; i++) {
616 int u = edges[i][0], v = edges[i][1];
617 hld.add_edge(u - 1, v - 1);
618 }
619 hld.init();
620 for (const auto &q : queries) {
621 int type = q[0];
622 if (type == 1) {
623 int p = q[1], x = q[2];
624 hld.update(p - 1, x);
625 } else if (type == 2) {
626 int a = q[1], b = q[2];
627 code_result.push_back(hld.query(a - 1, b - 1));
628 } else {
629 continue;
630 }
631 }
632 for (int i = 0; i < static_cast<int>(expected_result.size()); i++) {
633 assert(expected_result[i] == code_result[i]);
634 }
635 std::cout << "\nTest3 passed!\n";
636}
637
641int main() {
642 test_1();
643 test_2();
644 test_3();
645 return 0;
646}
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.
HLD(int nodes)
Class parameterized constructor. Resizes the and initilizes the data members.
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)
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()
#define ll
Heavy light decomposition algorithm.
for std::vector