Skip to content

Commit d983f1b

Browse files
author
Nadim-Mahmud
committed
hld added
1 parent ddbc3ac commit d983f1b

File tree

1 file changed

+274
-0
lines changed

1 file changed

+274
-0
lines changed
+274
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/**
2+
Descripton :
3+
Source :https://blog.anudeep2011.com/heavy-light-decomposition/
4+
*/
5+
6+
7+
#include <cstdio>
8+
#include <vector>
9+
using namespace std;
10+
11+
#define root 0
12+
#define N 10100
13+
#define LN 14
14+
15+
vector <int> adj[N], costs[N], indexx[N];
16+
int baseArray[N], ptr;
17+
int chainNo, chainInd[N], chainHead[N], posInBase[N];
18+
int depth[N], pa[LN][N], otherEnd[N], subsize[N];
19+
int st[N*6], qt[N*6];
20+
21+
/*
22+
* make_tree:
23+
* Used to construct the segment tree. It uses the baseArray for construction
24+
*/
25+
void make_tree(int cur, int s, int e) {
26+
if(s == e-1) {
27+
st[cur] = baseArray[s];
28+
return;
29+
}
30+
int c1 = (cur<<1), c2 = c1 | 1, m = (s+e)>>1;
31+
make_tree(c1, s, m);
32+
make_tree(c2, m, e);
33+
st[cur] = st[c1] > st[c2] ? st[c1] : st[c2];
34+
}
35+
36+
/*
37+
* update_tree:
38+
* Point update. Update a single element of the segment tree.
39+
*/
40+
void update_tree(int cur, int s, int e, int x, int val) {
41+
if(s > x || e <= x) return;
42+
if(s == x && s == e-1) {
43+
st[cur] = val;
44+
return;
45+
}
46+
int c1 = (cur<<1), c2 = c1 | 1, m = (s+e)>>1;
47+
update_tree(c1, s, m, x, val);
48+
update_tree(c2, m, e, x, val);
49+
st[cur] = st[c1] > st[c2] ? st[c1] : st[c2];
50+
}
51+
52+
/*
53+
* query_tree:
54+
* Given S and E, it will return the maximum value in the range [S,E)
55+
*/
56+
void query_tree(int cur, int s, int e, int S, int E) {
57+
if(s >= E || e <= S) {
58+
qt[cur] = -1;
59+
return;
60+
}
61+
if(s >= S && e <= E) {
62+
qt[cur] = st[cur];
63+
return;
64+
}
65+
int c1 = (cur<<1), c2 = c1 | 1, m = (s+e)>>1;
66+
query_tree(c1, s, m, S, E);
67+
query_tree(c2, m, e, S, E);
68+
qt[cur] = qt[c1] > qt[c2] ? qt[c1] : qt[c2];
69+
}
70+
71+
/*
72+
* query_up:
73+
* It takes two nodes u and v, condition is that v is an ancestor of u
74+
* We query the chain in which u is present till chain head, then move to next chain up
75+
* We do that way till u and v are in the same chain, we query for that part of chain and break
76+
*/
77+
78+
int query_up(int u, int v) {
79+
if(u == v) return 0; // Trivial
80+
int uchain, vchain = chainInd[v], ans = -1;
81+
// uchain and vchain are chain numbers of u and v
82+
while(1) {
83+
uchain = chainInd[u];
84+
if(uchain == vchain) {
85+
// Both u and v are in the same chain, so we need to query from u to v, update answer and break.
86+
// We break because we came from u up till v, we are done
87+
if(u==v) break;
88+
query_tree(1, 0, ptr, posInBase[v]+1, posInBase[u]+1);
89+
// Above is call to segment tree query function
90+
if(qt[1] > ans) ans = qt[1]; // Update answer
91+
break;
92+
}
93+
query_tree(1, 0, ptr, posInBase[chainHead[uchain]], posInBase[u]+1);
94+
// Above is call to segment tree query function. We do from chainHead of u till u. That is the whole chain from
95+
// start till head. We then update the answer
96+
if(qt[1] > ans) ans = qt[1];
97+
u = chainHead[uchain]; // move u to u's chainHead
98+
u = pa[0][u]; //Then move to its parent, that means we changed chains
99+
}
100+
return ans;
101+
}
102+
103+
/*
104+
* LCA:
105+
* Takes two nodes u, v and returns Lowest Common Ancestor of u, v
106+
*/
107+
int LCA(int u, int v) {
108+
if(depth[u] < depth[v]) swap(u,v);
109+
int diff = depth[u] - depth[v];
110+
for(int i=0; i<LN; i++) if( (diff>>i)&1 ) u = pa[i][u];
111+
if(u == v) return u;
112+
for(int i=LN-1; i>=0; i--) if(pa[i][u] != pa[i][v]) {
113+
u = pa[i][u];
114+
v = pa[i][v];
115+
}
116+
return pa[0][u];
117+
}
118+
119+
void query(int u, int v) {
120+
/*
121+
* We have a query from u to v, we break it into two queries, u to LCA(u,v) and LCA(u,v) to v
122+
*/
123+
int lca = LCA(u, v);
124+
int ans = query_up(u, lca); // One part of path
125+
int temp = query_up(v, lca); // another part of path
126+
if(temp > ans) ans = temp; // take the maximum of both paths
127+
printf("%d\n", ans);
128+
}
129+
130+
/*
131+
* change:
132+
* We just need to find its position in segment tree and update it
133+
*/
134+
void change(int i, int val) {
135+
int u = otherEnd[i];
136+
update_tree(1, 0, ptr, posInBase[u], val);
137+
}
138+
139+
/*
140+
* Actual HL-Decomposition part
141+
* Initially all entries of chainHead[] are set to -1.
142+
* So when ever a new chain is started, chain head is correctly assigned.
143+
* As we add a new node to chain, we will note its position in the baseArray.
144+
* In the first for loop we find the child node which has maximum sub-tree size.
145+
* The following if condition is failed for leaf nodes.
146+
* When the if condition passes, we expand the chain to special child.
147+
* In the second for loop we recursively call the function on all normal nodes.
148+
* chainNo++ ensures that we are creating a new chain for each normal child.
149+
*/
150+
void HLD(int curNode, int cost, int prev) {
151+
if(chainHead[chainNo] == -1) {
152+
chainHead[chainNo] = curNode; // Assign chain head
153+
}
154+
chainInd[curNode] = chainNo;
155+
posInBase[curNode] = ptr; // Position of this node in baseArray which we will use in Segtree
156+
baseArray[ptr++] = cost;
157+
158+
int sc = -1, ncost;
159+
// Loop to find special child
160+
for(int i=0; i<adj[curNode].size(); i++) if(adj[curNode][i] != prev) {
161+
if(sc == -1 || subsize[sc] < subsize[adj[curNode][i]]) {
162+
sc = adj[curNode][i];
163+
ncost = costs[curNode][i];
164+
}
165+
}
166+
167+
if(sc != -1) {
168+
// Expand the chain
169+
HLD(sc, ncost, curNode);
170+
}
171+
172+
for(int i=0; i<adj[curNode].size(); i++) if(adj[curNode][i] != prev) {
173+
if(sc != adj[curNode][i]) {
174+
// New chains at each normal node
175+
chainNo++;
176+
HLD(adj[curNode][i], costs[curNode][i], curNode);
177+
}
178+
}
179+
}
180+
181+
/*
182+
* dfs used to set parent of a node, depth of a node, subtree size of a node
183+
*/
184+
void dfs(int cur, int prev, int _depth=0) {
185+
pa[0][cur] = prev;
186+
depth[cur] = _depth;
187+
subsize[cur] = 1;
188+
for(int i=0; i<adj[cur].size(); i++)
189+
if(adj[cur][i] != prev) {
190+
otherEnd[indexx[cur][i]] = adj[cur][i];
191+
dfs(adj[cur][i], cur, _depth+1);
192+
subsize[cur] += subsize[adj[cur][i]];
193+
}
194+
}
195+
196+
int main() {
197+
int t;
198+
scanf("%d ", &t);
199+
while(t--) {
200+
ptr = 0;
201+
int n;
202+
scanf("%d", &n);
203+
// Cleaning step, new test case
204+
for(int i=0; i<n; i++) {
205+
adj[i].clear();
206+
costs[i].clear();
207+
indexx[i].clear();
208+
chainHead[i] = -1;
209+
for(int j=0; j<LN; j++) pa[j][i] = -1;
210+
}
211+
for(int i=1; i<n; i++) {
212+
int u, v, c;
213+
scanf("%d %d %d", &u, &v, &c);
214+
u--; v--;
215+
adj[u].push_back(v);
216+
costs[u].push_back(c);
217+
indexx[u].push_back(i-1);
218+
adj[v].push_back(u);
219+
costs[v].push_back(c);
220+
indexx[v].push_back(i-1);
221+
}
222+
223+
chainNo = 0;
224+
dfs(root, -1); // We set up subsize, depth and parent for each node
225+
HLD(root, -1, -1); // We decomposed the tree and created baseArray
226+
make_tree(1, 0, ptr); // We use baseArray and construct the needed segment tree
227+
228+
// Below Dynamic programming code is for LCA.
229+
for(int i=1; i<LN; i++)
230+
for(int j=0; j<n; j++)
231+
if(pa[i-1][j] != -1)
232+
pa[i][j] = pa[i-1][pa[i-1][j]];
233+
234+
while(1) {
235+
char s[100];
236+
scanf("%s", s);
237+
if(s[0]=='D') {
238+
break;
239+
}
240+
int a, b;
241+
scanf("%d %d", &a, &b);
242+
if(s[0]=='Q') {
243+
query(a-1, b-1);
244+
} else {
245+
change(a-1, b);
246+
}
247+
}
248+
}
249+
}
250+
251+
/**problem:
252+
253+
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1.
254+
255+
We will ask you to perfrom some instructions of the following form:
256+
257+
CHANGE i ti : change the cost of the i-th edge to ti
258+
or
259+
QUERY a b : ask for the maximum edge cost on the path from node a to node b
260+
261+
Input
262+
263+
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
264+
265+
For each test case:
266+
267+
In the first line there is an integer N (N <= 10000),
268+
In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
269+
The next lines contain instructions "CHANGE i ti" or "QUERY a b",
270+
The end of each test case is signified by the string "DONE".
271+
272+
There is one blank line between successive tests.
273+
274+
*/

0 commit comments

Comments
 (0)