1
1
package com .thealgorithms .tree ;
2
2
3
+ import java .util .ArrayList ;
4
+ import java .util .List ;
5
+
3
6
/**
4
7
* Heavy-Light Decomposition (HLD) implementation in Java.
5
8
*
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.
8
12
*
9
13
* Wikipedia Reference: https://en.wikipedia.org/wiki/Heavy-light_decomposition
10
14
*
11
15
* Author: Nithin U.
12
16
* Github: https://github.com/NithinU2802
13
- *
14
17
*/
15
18
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 ;
18
24
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
+ }
24
42
25
- public int getPosition (int index ){
43
+ public int getPosition (int index ) {
26
44
return position [index ];
27
- }
45
+ }
28
46
29
- public int getPositionIndex (){
47
+ public int getPositionIndex () {
30
48
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
+ }
43
149
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