11package org .gd .common ;
22
3+ import java .util .LinkedList ;
4+
35/**
46 * https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/
57 *
@@ -13,18 +15,13 @@ public class SegmentTree {
1315 private final int [] tree ;
1416 private final int length ;
1517
16- SegmentTree (int [] arr ) {
18+ public SegmentTree (int [] arr ) {
1719 this (arr , 0 , arr .length );
1820 }
1921
20- public static void main (String [] args ) {
21- SegmentTree segmentTree = new SegmentTree (new int []{0 , 1 , 2 , 3 });
22- System .out .println (segmentTree );
23- }
24-
2522 /**
2623 * Constructor to construct segment tree from given array. This constructor allocates memory for segment tree and
27- * calls {@link #constructSTUtil (int, int, int)} to fill the allocated memory
24+ * calls {@link #construct (int, int, int)} to fill the allocated memory
2825 *
2926 * @see Commons#log(double, double)
3027 */
@@ -35,15 +32,24 @@ private SegmentTree(int[] arr, int startIndex, int length) {
3532
3633 // Allocate memory for segment tree
3734 // Height of segment tree
38- int x = (int ) (Math .ceil (Math .log (length ) / Math .log (2 )));
35+ int treeHeight = (int ) (Math .ceil (Math .log (length ) / Math .log (2 )));
3936
4037 // Maximum size of segment tree
41- int maxSize = 2 * (int ) Math .pow (2 , x ) - 1 ;
38+
39+ //int maxSize = 2 * (int) Math.pow(2, x) - 1;
40+ int arrayTreeSize = (2 << treeHeight ) - 1 ;
4241
4342 // Memory allocation
44- tree = new int [maxSize ];
43+ tree = new int [arrayTreeSize ];
4544
46- constructSTUtil (startIndex , startIndex + length - 1 , 0 );
45+ construct (startIndex , startIndex + length - 1 , 0 );
46+ }
47+
48+ /**
49+ * A utility function to get the middle index from corner indexes.
50+ */
51+ private static int getMid (int leftBound , int rightBound ) {
52+ return leftBound + ((rightBound - leftBound ) >> 1 );
4753 }
4854
4955 /**
@@ -53,71 +59,50 @@ private SegmentTree(int[] arr, int startIndex, int length) {
5359 * @param rightBound right bound (inclusive)
5460 * @param treeIndex is index of current node in segment tree {@link #tree}
5561 */
56- private int constructSTUtil (int leftBound , int rightBound , int treeIndex ) {
62+ private int construct (int leftBound , int rightBound , int treeIndex ) {
5763
5864 // If there is one element in array, store it in current node of segment tree and return
5965 if (leftBound == rightBound )
6066 return tree [treeIndex ] = arr [leftBound ];
6167
6268 // If there are more than one elements, then recur for left and
6369 // right subtrees and store the sum of values in this node
64- int mid = getMid (leftBound , rightBound );
65-
66- int leftSum = constructSTUtil (leftBound , mid , ((treeIndex << 1 ) + 1 ));
67- int rightSum = constructSTUtil ((mid + 1 ), rightBound , ((treeIndex << 1 ) + 2 ));
70+ final int mid = getMid (leftBound , rightBound );
6871
69- tree [treeIndex ] = leftSum + rightSum ;
72+ final int leftSum = construct (leftBound , mid , (treeIndex * 2 + 1 ));
73+ final int rightSum = construct ((mid + 1 ), rightBound , (treeIndex * 2 + 2 ));
7074
71- return tree [treeIndex ];
75+ return tree [treeIndex ] = leftSum + rightSum ;
7276 }
7377
7478 /**
75- * A utility function to get the middle index from corner indexes.
76- */
77- private static int getMid (int leftBound , int rightBound ) {
78- return leftBound + ((rightBound - leftBound ) >> 1 );
79- }
80-
81- /*
82- A recursive function to get the sum of values in given range
83- of the array. The following are parameters for this function.
84-
85- st --> Pointer to segment tree
86- si --> Index of current node in the segment tree. Initially
87- 0 is passed as root is always at index 0
88- leftBound & rightBound --> Starting and ending indexes of the segment represented
89- by current node, i.e., st[si]
90- qs & qe --> Starting and ending indexes of query range
91-
79+ * The function to update a value in input array and segment tree. It uses updateValueUtil() to update the value in
80+ * segment tree
9281 */
82+ public void update (int index , int value ) {
9383
94- private int getSumUtil (int leftBound , int rightBound , int qs , int qe , int si ) {
95- // If segment of this node is a part of given range, then return
96- // the sum of the segment
97- if (qs <= leftBound && qe >= rightBound )
98- return tree [si ];
99-
100- // If segment of this node is outside the given range
101- if (rightBound < qs || leftBound > qe )
102- return 0 ;
84+ if (index < 0 || index > length - 1 )
85+ throw new IndexOutOfBoundsException ();
10386
104- // If a part of this segment overlaps with the given range
105- int mid = getMid ( leftBound , rightBound ) ;
87+ // Get the difference between new value and old value
88+ int diff = value - arr [ index ] ;
10689
107- int leftSum = getSumUtil ( leftBound , mid , qs , qe , ( 2 * si + 1 ));
108- int rightSum = getSumUtil (( mid + 1 ), rightBound , qs , qe , ( 2 * si + 2 )) ;
90+ // Update the value in array
91+ arr [ index ] = value ;
10992
110- return leftSum + rightSum ;
93+ // Update the values of nodes in segment tree
94+ updateValueUtil (0 , length - 1 , index , diff , 0 );
11195 }
11296
113- /*
114- A recursive function to update the nodes which have the given
115- index in their range. The following are parameters
116- st, si, ss and se are same as getSumUtil()
117- i --> index of the element to be updated. This index is in
118- input array.
119- diff --> Value to be added to all nodes which have i in range
120- */
97+ /**
98+ * A recursive function to update the nodes which have the given index in their range. The following are parameters
99+ *
100+ * @param leftBound Starting indexes of the segment represented by current node
101+ * @param rightBound ending indexes of the segment represented by current node, i.e., st[si]
102+ * @param index index of the element to be updated. This index is in input array
103+ * @param diff Value to be added to all nodes which have i in range
104+ * @param treeIndex Index of current node in the segment tree. Initially 0 is passed as root is always at index 0
105+ */
121106 private void updateValueUtil (int leftBound , int rightBound , int index , int diff , int treeIndex ) {
122107 // Base Case: If the input index lies outside the range of
123108 // this segment
@@ -135,34 +120,67 @@ private void updateValueUtil(int leftBound, int rightBound, int index, int diff,
135120 }
136121
137122 /**
138- * The function to update a value in input array and segment tree. It uses updateValueUtil() to update the value in
139- * segment tree
123+ * It mainly uses {@link #getSumUtil(int, int, int, int, int)}
124+ *
125+ * @return sum of elements in range from index qs (quey start) to qe (query end).
140126 */
141- void updateValue (int index , int value ) {
127+ public int getSum (int leftBound , int rightBound ) {
142128
143- if (index < 0 || index > length - 1 )
129+ if (leftBound < 0 || rightBound > length - 1 || leftBound > rightBound )
144130 throw new IndexOutOfBoundsException ();
145131
146- // Get the difference between new value and old value
147- int diff = value - arr [index ];
148-
149- // Update the value in array
150- arr [index ] = value ;
151-
152- // Update the values of nodes in segment tree
153- updateValueUtil (0 , length - 1 , index , diff , 0 );
132+ return getSumUtil (0 , length - 1 , leftBound , rightBound , 0 );
154133 }
155134
156135 /**
157- * It mainly uses {@link #getSumUtil(int, int, int, int, int)}
136+ * A recursive function to get the sum of values in given range of the array. The following are parameters for this
137+ * function.
158138 *
159- * @return sum of elements in range from index qs (quey start) to qe (query end).
139+ * @param treeIndex Index of current node in the segment tree. Initially 0 is passed as root is always at index
140+ * 0
141+ * @param treeLeftBound Starting indexes of the segment represented by current node
142+ * @param treeRightBound ending indexes of the segment represented by current node, i.e., st[si]
143+ * @param leftBound Starting indexes of query range
144+ * @param rightBound ending indexes of query range
160145 */
161- int getSum (int leftBound , int rightBound ) {
146+ private int getSumUtil (int treeLeftBound , int treeRightBound , int leftBound , int rightBound , int treeIndex ) {
162147
163- if (leftBound < 0 || rightBound > length - 1 || leftBound > rightBound )
164- throw new IndexOutOfBoundsException ();
148+ // If segment of this node is a part of given range, then return
149+ // the sum of the segment
150+ if (leftBound <= treeLeftBound && rightBound >= treeRightBound )
151+ return tree [treeIndex ];
165152
166- return getSumUtil (0 , length - 1 , leftBound , rightBound , 0 );
153+ // If segment of this node is outside the given range
154+ if (treeRightBound < leftBound || treeLeftBound > rightBound )
155+ return 0 ;
156+
157+ // If a part of this segment overlaps with the given range
158+ int mid = getMid (treeLeftBound , treeRightBound );
159+
160+ int leftSum = getSumUtil (treeLeftBound , mid , leftBound , rightBound , (treeIndex * 2 + 1 ));
161+ int rightSum = getSumUtil ((mid + 1 ), treeRightBound , leftBound , rightBound , (treeIndex * 2 + 2 ));
162+
163+ return leftSum + rightSum ;
164+ }
165+
166+ @ Override
167+ public String toString () {
168+
169+ String format = "%" + Commons .maxDigitsCount (tree ) + "d " ;
170+
171+ LinkedList <int []> q = new LinkedList <>();
172+ q .add (new int []{0 , 1 });
173+ int [] bounds ;
174+ StringBuilder sb = new StringBuilder ();
175+ while ((bounds = q .poll ()) != null ) {
176+ for (int i = bounds [0 ]; i < Math .min (tree .length , bounds [1 ]); i ++) {
177+ sb .append (String .format (format , tree [i ]));
178+ }
179+ sb .append ('\n' );
180+ if (bounds [1 ] < tree .length ) {
181+ q .add (new int []{bounds [1 ], (bounds [1 ] << 1 ) + 1 });
182+ }
183+ }
184+ return sb .toString ();
167185 }
168186}
0 commit comments