Skip to content

Commit b13db0e

Browse files
committed
Format Update
1 parent 4df8542 commit b13db0e

File tree

2 files changed

+153
-197
lines changed

2 files changed

+153
-197
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,158 @@
11
package com.thealgorithms.tree;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
36
/**
47
* Heavy-Light Decomposition (HLD) implementation in Java.
58
*
6-
* HLD is used to efficiently handle path queries on trees, such as maximum, sum, or updates.
7-
* It decomposes the tree into heavy and light chains, enabling queries in O(log N) time.
9+
* HLD is used to efficiently handle path queries on trees, such as maximum,
10+
* sum, or updates. It decomposes the tree into heavy and light chains,
11+
* enabling queries in O(log N) time.
812
*
913
* Wikipedia Reference: https://en.wikipedia.org/wiki/Heavy-light_decomposition
1014
*
1115
* Author: Nithin U.
1216
* Github: https://github.com/NithinU2802
13-
*
1417
*/
1518

16-
import java.util.ArrayList;
17-
import java.util.List;
19+
public class HeavyLightDecomposition {
20+
private List<Integer>[] tree;
21+
private int[] parent, depth, subtreeSize, chainHead, position, nodeValue;
22+
private int[] segmentTree;
23+
private int positionIndex;
1824

19-
public class HeavyLightDecomposition {
20-
private List<Integer>[] tree;
21-
private int[] parent, depth, subtreeSize, chainHead, position, nodeValue;
22-
private int[] segmentTree;
23-
private int positionIndex;
25+
@SuppressWarnings("unchecked")
26+
public HeavyLightDecomposition(int n) {
27+
tree = new ArrayList[n + 1];
28+
parent = new int[n + 1];
29+
depth = new int[n + 1];
30+
subtreeSize = new int[n + 1];
31+
chainHead = new int[n + 1];
32+
position = new int[n + 1];
33+
nodeValue = new int[n + 1];
34+
segmentTree = new int[4 * (n + 1)];
35+
36+
for (int i = 0; i <= n; i++) {
37+
tree[i] = new ArrayList<>();
38+
chainHead[i] = -1;
39+
}
40+
positionIndex = 0;
41+
}
2442

25-
public int getPosition(int index){
43+
public int getPosition(int index) {
2644
return position[index];
27-
}
45+
}
2846

29-
public int getPositionIndex(){
47+
public int getPositionIndex() {
3048
return positionIndex;
31-
}
32-
33-
@SuppressWarnings("unchecked")
34-
public HeavyLightDecomposition(int n) {
35-
tree = new ArrayList[n + 1]; // Causes "unchecked or unsafe operations" warning
36-
parent = new int[n + 1];
37-
depth = new int[n + 1];
38-
subtreeSize = new int[n + 1];
39-
chainHead = new int[n + 1];
40-
position = new int[n + 1];
41-
nodeValue = new int[n + 1];
42-
segmentTree = new int[4 * (n + 1)];
49+
}
50+
51+
public void addEdge(int u, int v) {
52+
tree[u].add(v);
53+
tree[v].add(u);
54+
}
55+
56+
private void dfsSize(int node, int parentNode) {
57+
parent[node] = parentNode;
58+
subtreeSize[node] = 1;
59+
60+
for (int child : tree[node]) {
61+
if (child != parentNode) {
62+
depth[child] = depth[node] + 1;
63+
dfsSize(child, node);
64+
subtreeSize[node] += subtreeSize[child];
65+
}
66+
}
67+
}
68+
69+
private void decompose(int node, int head) {
70+
chainHead[node] = head;
71+
position[node] = positionIndex++;
72+
73+
int heavyChild = -1, maxSubtreeSize = -1;
74+
for (int child : tree[node]) {
75+
if (child != parent[node] && subtreeSize[child] > maxSubtreeSize) {
76+
heavyChild = child;
77+
maxSubtreeSize = subtreeSize[child];
78+
}
79+
}
80+
81+
if (heavyChild != -1) {
82+
decompose(heavyChild, head);
83+
}
84+
85+
for (int child : tree[node]) {
86+
if (child != parent[node] && child != heavyChild) {
87+
decompose(child, child);
88+
}
89+
}
90+
}
91+
92+
private void buildSegmentTree(int node, int start, int end) {
93+
if (start == end) {
94+
segmentTree[node] = nodeValue[start];
95+
return;
96+
}
97+
int mid = (start + end) / 2;
98+
buildSegmentTree(2 * node, start, mid);
99+
buildSegmentTree(2 * node + 1, mid + 1, end);
100+
segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]);
101+
}
102+
103+
public void updateSegmentTree(int node, int start, int end, int index, int value) {
104+
if (start == end) {
105+
segmentTree[node] = value;
106+
return;
107+
}
108+
int mid = (start + end) / 2;
109+
if (index <= mid) {
110+
updateSegmentTree(2 * node, start, mid, index, value);
111+
} else {
112+
updateSegmentTree(2 * node + 1, mid + 1, end, index, value);
113+
}
114+
segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]);
115+
}
116+
117+
public int querySegmentTree(int node, int start, int end, int left, int right) {
118+
if (left > end || right < start) {
119+
return Integer.MIN_VALUE;
120+
}
121+
if (left <= start && end <= right) {
122+
return segmentTree[node];
123+
}
124+
int mid = (start + end) / 2;
125+
int leftQuery = querySegmentTree(2 * node, start, mid, left, right);
126+
int rightQuery = querySegmentTree(2 * node + 1, mid + 1, end, left, right);
127+
return Math.max(leftQuery, rightQuery);
128+
}
129+
130+
public int queryMaxInPath(int u, int v) {
131+
int result = Integer.MIN_VALUE;
132+
while (chainHead[u] != chainHead[v]) {
133+
if (depth[chainHead[u]] < depth[chainHead[v]]) {
134+
int temp = u;
135+
u = v;
136+
v = temp;
137+
}
138+
result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[chainHead[u]], position[u]));
139+
u = parent[chainHead[u]];
140+
}
141+
if (depth[u] > depth[v]) {
142+
int temp = u;
143+
u = v;
144+
v = temp;
145+
}
146+
result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[u], position[v]));
147+
return result;
148+
}
43149

44-
for (int i = 0; i <= n; i++) {
45-
tree[i] = new ArrayList<>();
46-
chainHead[i] = -1;
47-
}
48-
positionIndex = 0;
49-
}
50-
51-
/**
52-
* Adds an edge to the tree.
53-
*/
54-
public void addEdge(int u, int v) {
55-
tree[u].add(v);
56-
tree[v].add(u);
57-
}
58-
59-
/**
60-
* First DFS to calculate subtree sizes and determine heavy children.
61-
*/
62-
private void dfsSize(int node, int parentNode) {
63-
parent[node] = parentNode;
64-
subtreeSize[node] = 1;
65-
66-
for (int child : tree[node]) {
67-
if (child != parentNode) {
68-
depth[child] = depth[node] + 1;
69-
dfsSize(child, node);
70-
subtreeSize[node] += subtreeSize[child];
71-
}
72-
}
73-
}
74-
75-
/**
76-
* Second DFS to perform Heavy-Light Decomposition.
77-
*/
78-
private void decompose(int node, int head) {
79-
chainHead[node] = head;
80-
position[node] = positionIndex++;
81-
82-
int heavyChild = -1, maxSubtreeSize = -1;
83-
84-
for (int child : tree[node]) {
85-
if (child != parent[node] && subtreeSize[child] > maxSubtreeSize) {
86-
heavyChild = child;
87-
maxSubtreeSize = subtreeSize[child];
88-
}
89-
}
90-
91-
if (heavyChild != -1) {
92-
decompose(heavyChild, head);
93-
}
94-
95-
for (int child : tree[node]) {
96-
if (child != parent[node] && child != heavyChild) {
97-
decompose(child, child);
98-
}
99-
}
100-
}
101-
102-
/**
103-
* Builds a Segment Tree to handle path queries efficiently.
104-
*/
105-
private void buildSegmentTree(int node, int start, int end) {
106-
if (start == end) {
107-
segmentTree[node] = nodeValue[start];
108-
return;
109-
}
110-
111-
int mid = (start + end) / 2;
112-
buildSegmentTree(2 * node, start, mid);
113-
buildSegmentTree(2 * node + 1, mid + 1, end);
114-
115-
segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]);
116-
}
117-
118-
/**
119-
* Updates a node's value in the Segment Tree.
120-
*/
121-
public void updateSegmentTree(int node, int start, int end, int index, int value) {
122-
if (start == end) {
123-
segmentTree[node] = value;
124-
return;
125-
}
126-
127-
int mid = (start + end) / 2;
128-
if (index <= mid) {
129-
updateSegmentTree(2 * node, start, mid, index, value);
130-
} else {
131-
updateSegmentTree(2 * node + 1, mid + 1, end, index, value);
132-
}
133-
134-
segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]);
135-
}
136-
137-
/**
138-
* Queries the Segment Tree for the maximum value in a given range.
139-
*/
140-
public int querySegmentTree(int node, int start, int end, int left, int right) {
141-
if (left > end || right < start) {
142-
return Integer.MIN_VALUE;
143-
}
144-
145-
if (left <= start && end <= right) {
146-
return segmentTree[node];
147-
}
148-
149-
int mid = (start + end) / 2;
150-
int leftQuery = querySegmentTree(2 * node, start, mid, left, right);
151-
int rightQuery = querySegmentTree(2 * node + 1, mid + 1, end, left, right);
152-
153-
return Math.max(leftQuery, rightQuery);
154-
}
155-
156-
/**
157-
* Queries the maximum value in the path from node u to node v.
158-
*/
159-
public int queryMaxInPath(int u, int v) {
160-
int result = Integer.MIN_VALUE;
161-
162-
while (chainHead[u] != chainHead[v]) {
163-
if (depth[chainHead[u]] < depth[chainHead[v]]) {
164-
int temp = u;
165-
u = v;
166-
v = temp;
167-
}
168-
169-
result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[chainHead[u]], position[u]));
170-
u = parent[chainHead[u]];
171-
}
172-
173-
if (depth[u] > depth[v]) {
174-
int temp = u;
175-
u = v;
176-
v = temp;
177-
}
178-
179-
result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[u], position[v]));
180-
return result;
181-
}
182-
183-
/**
184-
* Initializes the HLD structure and Segment Tree.
185-
*/
186-
public void initialize(int root, int[] values) {
187-
dfsSize(root, -1);
188-
decompose(root, root);
189-
for (int i = 0; i < values.length; i++) {
190-
nodeValue[position[i]] = values[i];
191-
}
192-
buildSegmentTree(1, 0, positionIndex - 1);
193-
}
194-
195-
}
196-
150+
public void initialize(int root, int[] values) {
151+
dfsSize(root, -1);
152+
decompose(root, root);
153+
for (int i = 0; i < values.length; i++) {
154+
nodeValue[position[i]] = values[i];
155+
}
156+
buildSegmentTree(1, 0, positionIndex - 1);
157+
}
158+
}

0 commit comments

Comments
 (0)