diff --git a/algorithms/graph/hld.cpp b/algorithms/graph/hld.cpp
index 777dc7b334643633963c77ad3dce1ef87a077837..b6b58e473b96e5e70dedfc082a95c5ad43bad4dc 100644
--- a/algorithms/graph/hld.cpp
+++ b/algorithms/graph/hld.cpp
@@ -5,11 +5,14 @@
 ///   - query: O(log^2 n)
 ///   - update: O(log n)
 /// Space: O(n log n)
-
-#define LOG 20 // log2(MAX)
+/// 
+/// Caution:
+///   - Modifications are necessary if values are associated to vertices;
+///   - Modifications are necerrary if other data structure is used.
+/// 
+/// Status: Tested (QTREE,URI2887)
 
 ii edge[MAX];
-int par[MAX][LOG];
 vector<ii> graph[MAX];
  
 template <typename ST>
@@ -17,124 +20,85 @@ struct HLD {
   ST &seg;
   int cnum, ptr;
   
-  // Size of subtree, and depth
-  vector<int> size, dep;
+  // depth, parent, value of node
+  vector<int> dep, par, val;
 
-  // Chain's head, chain's index, base array for segtree, 
-  // position of node in base, and bottommost node
-  vector<int> chead, cidx, base, pos, bot;
+  // head[i]: head of i-th node's chain;
+  // heavy[i]: "special child" of i-th node
+  // pos[i]: position of i-th node on segtree
+  // bot[i]: bottommost (depth-wise) node on the i-th 
+  //   edge (required only when edges have weights)
+  vector<int> head, heavy, pos, bot;
  
   HLD(int n, ST &seg) :
-    seg(seg), size(n), dep(n, 0), bot(n),
-    chead(n, -1), cidx(n), base(n), pos(n)
+    seg(seg), 
+    dep(n, 0), par(n), val(n),
+    head(n), heavy(n, -1), pos(n), bot(n)
   {
-    mset(par, -1);
     cnum = ptr = 0;
  
+    N = n; // global N for segtree
     dfs(0);
     decompose(0);
- 
-    N = ptr; // global N for segtree
-    seg.build(base);
- 
-    // bot[i] stores the bottommost (depth-wise) node
-    // on the i-th edge
-    for (int i = 0; i < N - 1; ++i)
+
+    // (required only when edges have weights)
+    for (int i = 0; i < n - 1; ++i)
       if (dep[edge[i].fi] > dep[edge[i].se])
         bot[i] = edge[i].fi;
       else
         bot[i] = edge[i].se;
   }
  
-  void dfs(int x, int p = -1) {
-    size[x] = 1;
-    par[x][0] = p;
- 
-    for (int i = 1; i < LOG; ++i)
-      if (par[x][i - 1] != -1)
-        par[x][i] = par[par[x][i - 1]][i - 1];
+  int dfs(int x, int p = -1) {
+    int size = 1;
+    par[x] = p;
  
+    int max_size = 0;
     for (auto i : graph[x])
       if (i.fi != p) {
         dep[i.fi] = dep[x] + 1;
-        dfs(i.fi, x);
-        size[x] += size[i.fi];
+        val[i.fi] = i.se;
+        int isize = dfs(i.fi, x);
+
+        size += isize;
+        if (isize > max_size)
+          max_size = isize, heavy[x] = i.fi;
       }
+
+    return size;
   }
  
-  void decompose(int x, int c = -1, int p = -1) {
-    if (chead[cnum] == -1)
-      chead[cnum] = x;
- 
-    pos[x] = ptr;
-    cidx[x] = cnum;
-    base[ptr++] = c;
- 
-    ii sc(-1, -1);
-    if (graph[x].size() > 1) {
-      for (auto i : graph[x])
-        if (i.fi != p)
-          if (sc.fi == -1 || size[sc.fi] < size[i.fi])
-            sc = i;
+  void decompose(int x, int h = 0) {
+    head[x] = h;
+    seg.update(ptr, val[x]);
+    pos[x] = ptr++;
+
+    if (heavy[x] != -1)
+      decompose(heavy[x], h);
 
-      decompose(sc.fi, sc.se, x);
-    }
- 
     for (auto i : graph[x])
-      if (sc.fi != i.fi && i.fi != p) {
-        cnum++;
-        decompose(i.fi, i.se, x); 
-      }
+      if (i.fi != par[x] && i.fi != heavy[x])
+        decompose(i.fi, i.fi);
   }
  
-  int query_up(int a, int b) {
-    if (a == b) return 0;
- 
-    int ca, cb = cidx[b], ans = -1;
-    while (1) {
-      ca = cidx[a];
-      if (ca == cb) {
-        if (a == b) break;
-        ans = max(ans, seg.query(pos[b] + 1, pos[a]));
-        break;
-      }
- 
-      ans = max(ans, seg.query(pos[chead[ca]], pos[a]));
-      a = par[chead[ca]][0];
+  // Queries max edge (or vertice) on the path 
+  // between a and b
+  int query(int a, int b) {
+    int ans = seg.ident;
+    for (; head[a] != head[b]; b = par[head[b]]) {
+      if (dep[head[a]] > dep[head[b]])
+        swap(a, b);
+      ans = seg.op(ans, seg.query(pos[head[b]], pos[b]));
     }
- 
-    return ans;
-  }
- 
-  int lca(int a, int b) {
-    int ans = 0;
- 
-    if (dep[a] < dep[b])
+
+    if (dep[a] > dep[b])
       swap(a, b);
- 
-    for (int i = LOG - 1; i >= 0; --i)
-      if (par[a][i] != -1 && dep[par[a][i]] >= dep[b])
-        a = par[a][i];
- 
-    if (a == b)
-      return a;
- 
-    for (int i = LOG - 1; i >= 0; --i)
-      if (par[a][i] != -1 && par[a][i] != par[b][i]) {
-        a = par[a][i];
-        b = par[b][i];
-      }
- 
-    return par[a][0];
-  }
- 
-  // Queries max edge on the path between a and b
-  int query(int a, int b) {
-    int lab = lca(a, b);
-    return max(query_up(a, lab), query_up(b, lab));
+
+    // Remove "+ 1" when values are associated with vertices
+    return seg.op(ans, seg.query(pos[a] + 1, pos[b]));
   }
  
-  // Updates value of i-th edge
+  // Updates value of i-th edge (or vertice)
   void update(int i, int val) {
     seg.update(pos[bot[i]], val);
   }