From f4504cac4433e10c7efd4589f44d7fd833acee57 Mon Sep 17 00:00:00 2001 From: Aniruthan R <67466816+aneee004@users.noreply.github.com> Date: Fri, 14 Aug 2020 01:17:47 +0530 Subject: [PATCH] Added function documentation TODO: Data member documentation. --- range_queries/heavy_light_decomposition.cpp | 206 +++++++++++++++----- 1 file changed, 161 insertions(+), 45 deletions(-) diff --git a/range_queries/heavy_light_decomposition.cpp b/range_queries/heavy_light_decomposition.cpp index 46df90e2f..5f3f2f828 100644 --- a/range_queries/heavy_light_decomposition.cpp +++ b/range_queries/heavy_light_decomposition.cpp @@ -1,4 +1,4 @@ -/* +/** * @file heavy_ligt_decomposition.cpp * @brief Heavy-Light Decomposition implementation * @author: [Aniruthan R](https://github.com/aneee004) @@ -6,7 +6,7 @@ * @CodeChef: aneee004 * @CodeForces: aneee * - * TODO: Support edge weight quereis, by storing the edge weight value in it's child + * TODO: Support edge weight queries, by storing the edge weight value in it's child * * algorithm verified by testing in CSES path queries: https://cses.fi/problemset/task/1138 */ @@ -53,13 +53,27 @@ * Sample I/O at the bottom. */ -/* A Basic Tree, which supports binary lifting */ +/** + * A Basic Tree, which supports binary lifting +*/ template class Tree { /* * Deleting the default constructor * An instance can only be created with the number of nodes */ + + /* Defaults: + * t_node indexing are zero based + * t_root is 0 + * depth of root_node is 0 + */ + + /* Supports: + * lift :- lift a node k units up the tree + * kth_ancestor :- returns the kth ancestor + * lca :- returns the least common ancestor + */ private: std::vector> t_adj; const int t_nodes, t_maxlift; @@ -68,13 +82,12 @@ private: int t_root; std::vector t_val; template friend class HLD; - - /* Defaults: - * t_node indexing are zero based - * t_root is 0 - * depth of root_node is 0 - */ + /** + * Utility function to compute sub-tree sizes + * @param u, current dfs node + * @param p, the parent of node @param u + */ void dfs_size(int u, int p = -1) { for(const int& v : t_adj[u]) { if(v^p) { @@ -84,6 +97,11 @@ private: } } + /** + * Utility function to populate the t_par vector + * @param u, current dfs node + * @param p, the parent of node @param u + */ void dfs_lca(int u, int p = -1) { t_par[u][0] = p; if(p != -1) t_depth[u] = 1 + t_depth[p]; @@ -101,6 +119,10 @@ private: } public: + /** + * Class parameterized constructor. Resizes the and initilizes the data members. + * @param nodes, the total number of nodes in the tree + */ explicit Tree(int nodes) : t_nodes(nodes), t_maxlift(static_cast(floor(log2(nodes))) + 1) { /* Initialize and resize all the vectors */ @@ -111,35 +133,51 @@ public: t_size.assign(t_nodes, 1); t_val.resize(t_nodes); } - + + /** + * Adds an undirected edge from node u to node v in the tree + * @param u, the node where the edge is from + * @param v, the node where the edge is to + */ void add_edge(const int u, const int v) { t_adj[u].push_back(v); t_adj[v].push_back(u); } + /** + * Set the root for the tree + * @param new_root, the new root + */ void change_root(int new_root) { t_root = new_root; } - + + /** + * Set the values for all the nodes + * @param node_val, a vector of size n, with all the node values + * where, n is the number of nodes + */ void set_node_val(std::vector node_val) { + assert(static_cast(node_val.size()) == t_nodes); t_val = node_val; } - /* Initialization, sizes and parents */ + /** + * This function must be called after the tree adjacency list and node values are populated + * The function initializes the required parametes, and populates the segment tree + */ void init() { assert(t_nodes > 0); dfs_size(t_root); dfs_lca(t_root); } - - /* Supports: - * lift :- lift a node k units up the tree - * kth_ancestor :- returns the kth ancestor - * lca :- returns the least common ancestor + /** + * The function lifts a node, k units up the tree + * @param p, a pointer to the variable that stores the node id + * @param dist, the distance to move up the tree + * @return, void. The node if, after lifting is stored in the address pointed by @param p. */ - - /* in place lift */ void lift(int* const p, int dist) { for(int k = 0; k < t_maxlift; k++) { if(*p == -1) return; @@ -150,13 +188,23 @@ public: } } - /* returns the kth ancestor */ + /** + * The function returns the kth ancestor of a node + * @param p, the node id whose kth ancestor is to be found + * @param dist, the distance to move up the tree + * @return, the kth ancestor of node @param p + */ int kth_ancestor(int p, const int& dist) { lift(&p, dist); return p; } - /* returns the least common ancestor */ + /** + * The function returns the least common ancestor of two nodes + * @param a, node id_1 + * @param b, node id_2 + * @return, the least common ancestor of node @param a, and node @param b + */ int lca(int a, int b) { assert(a >= 0 and b >= 0 and a < t_nodes and b < t_nodes); if(t_depth[a] > t_depth[b]) { @@ -176,18 +224,14 @@ public: } }; -/* Segment Tree, to store heavy chains */ +/** + * Segment Tree, to store heavy chains +*/ template class SG { private: - /* Change the sret_init, based on requirement: - * Sum Query: 0 (Default) - * XOR Query: 0 (Default) - * Min Query: Infinity - * Max Query: -Infinity - */ - - /* Everything here is private, + /** + * Everything here is private, * and can only be acced thought the methods, * in the derived class (HLD). */ @@ -196,23 +240,41 @@ private: int s_size; template friend class HLD; X sret_init = 0; + + /** + * Function that specifies the type of operation involved when segments are combined + * @param lhs, the left segment + * @param rhs, the right segment + * @return, the combined result + */ X combine(X lhs, X rhs) { return lhs + rhs; } - /* Construction requires a size */ + /** + * Class parameterized constructor. Resizes the and initilizes the data members. + * @param nodes, the total number of nodes in the tree + */ explicit SG(int size) { s_size = size; s_tree.assign(2*s_size, 0ll); } - /* update a segment tree node value */ + /** + * Update the value at a node + * @param p, the node to be udpated + * @param v, the update value + */ void update(int p, X v) { for(p += s_size; p > 0; p >>= 1) s_tree[p] += v; } - /* make a segment tree range query */ + /** + * Make a range query from node label l to node label r + * @param l, node label where the path starts + * @param r, node label where the path ends + */ X query(int l, int r) { X lhs = sret_init, rhs = sret_init; for(l += s_size, r += s_size + 1; l < r; l >>= 1, r >>= 1) { @@ -221,20 +283,35 @@ private: } return combine(lhs, rhs); } - - void set_sret_init(int new_sret_init) { + + /** + * Set the initialization for the query data type, based on requirement + * Change the sret_init, based on requirement: + * Sum Query: 0 (Default) + * XOR Query: 0 (Default) + * Min Query: Infinity + * Max Query: -Infinity + * @param new_sret_init, the new init + */ + void set_sret_init(X new_sret_init) { sret_init = new_sret_init; } }; -/* The Heavy-Light Decomposition class */ +/** + * The Heavy-Light Decomposition class +*/ template class HLD : public Tree, public SG { private: int label; std::vector h_label, h_heavychlid, h_parent; - /* Utility functions */ + /** + * Utility function to assign heavy child to each node (-1 for a leaf node) + * @param u, current dfs node + * @param p, the parent of node @param u + */ void dfs_hc(int u, int p = -1) { int hc_size = -1, hc_id = -1; for(const int& v : Tree::t_adj[u]) { @@ -248,7 +325,12 @@ private: } h_heavychlid[u] = hc_id; } - + + /** + * Utility function to assign highest parent that can be reached though heavy chains + * @param u, current dfs node + * @param p, the parent of node @param u + */ void dfs_par(int u, int p = -1) { if(h_heavychlid[u] != -1) { h_parent[h_heavychlid[u]] = h_parent[u]; @@ -260,7 +342,12 @@ private: } } } - + + /** + * Utility function to lable the nodes so that heavy chains have a contigous lable + * @param u, current dfs node + * @param p, the parent of node @param u + */ void dfs_labels(int u, int p = -1) { h_label[u] = label++; if(h_heavychlid[u] != -1) dfs_labels(h_heavychlid[u], u); @@ -270,7 +357,14 @@ private: } } } - + + /** + * Utility function to break down a path query into two chain queries + * @param a, node where the path starts + * @param b, node where the path ends + * a and b must belong to a single root to leaf chain + * @return, the sum of ndoe values in the simple path from a to b + */ X chain_query(int a, int b) { X ret = SG::sret_init; if(Tree::t_depth[a] < Tree::t_depth[b]) std::swap(a, b); @@ -287,6 +381,10 @@ private: return ret; } public: + /** + * Class parameterized constructor. Resizes the and initilizes the data members. + * @param nodes, the total number of nodes in the tree + */ explicit HLD(int nodes) : Tree(nodes), SG(nodes) { /* Initialization and resize vectors */ label = 0; @@ -296,7 +394,10 @@ public: iota(h_parent.begin(), h_parent.end(), 0); } - /* Initialization */ + /** + * This function must be called after the tree adjacency list and node values are populated + * The function initializes the required parametes, and populates the segment tree + */ void init() { Tree::init(); @@ -315,16 +416,23 @@ public: } } - /* Changes the value at node, to val */ + /** + * This function updates the value at node with val + * @param node, the node where the update is done + * @param val, the value that is being updated + */ void update(int node, X val) { X diff = val - Tree::t_val[node]; SG::update(h_label[node], diff); Tree::t_val[node] = val; } - /* - * return the (sum) of node values in, - * the simple path from a, to b + /** + * This function returns the sum of node values in the simple path from from node_1 to node_2 + * @param a the node where the simple path starts + * @param b the node where the simple path ends + * (parameters are interchangeable, i.e., the function is commutative) + * @return the sum of node values in the simple path from @param a to @param b */ X query(int a, int b) { int lc = Tree::lca(a, b); @@ -336,6 +444,9 @@ public: } }; +/** + * Test implementaions +*/ void test_1() { std::cout << "Test 1:\n"; /* Test details */ @@ -427,11 +538,16 @@ void test_2() { } } } + +/** + * Main funciton +*/ int main() { test_1(); test_2(); return 0; } + /* * Sample Output 1: * 11