@@ -38,6 +38,7 @@ public enum Operation {
3838 MIN ,
3939 MAX ,
4040 SUM ,
41+ MULT ,
4142 GCD
4243 };
4344
@@ -47,6 +48,7 @@ public enum Operation {
4748 private BinaryOperator <Long > sumFn = (a , b ) -> a + b ;
4849 private BinaryOperator <Long > minFn = (a , b ) -> Math .min (a , b );
4950 private BinaryOperator <Long > maxFn = (a , b ) -> Math .max (a , b );
51+ private BinaryOperator <Long > multFn = (a , b ) -> a * b ;
5052 private BinaryOperator <Long > gcdFn =
5153 (a , b ) -> {
5254 long gcd = a ;
@@ -106,6 +108,8 @@ private void init(long[] v) {
106108 }
107109 } else if (op == Operation .SUM ) {
108110 dp [i ][j ] = sumFn .apply (leftInterval , rightInterval );
111+ } else if (op == Operation .MULT ) {
112+ dp [i ][j ] = multFn .apply (leftInterval , rightInterval );
109113 } else if (op == Operation .GCD ) {
110114 dp [i ][j ] = gcdFn .apply (leftInterval , rightInterval );
111115 }
@@ -126,14 +130,21 @@ private void printTable() {
126130
127131 // Queries [l, r] for the operation set on this sparse table.
128132 public long query (int l , int r ) {
133+ // Fast queries types, O(1)
129134 if (op == Operation .MIN ) {
130135 return query (l , r , minFn );
131136 } else if (op == Operation .MAX ) {
132137 return query (l , r , maxFn );
133138 } else if (op == Operation .GCD ) {
134139 return query (l , r , gcdFn );
135140 }
136- return sumQuery (l , r );
141+
142+ // Slower query types, O(log2(n))
143+ if (op == Operation .SUM ) {
144+ return sumQuery (l , r );
145+ } else {
146+ return multQuery (l , r );
147+ }
137148 }
138149
139150 public int queryIndex (int l , int r ) {
@@ -148,7 +159,7 @@ public int queryIndex(int l, int r) {
148159
149160 private int minQueryIndex (int l , int r ) {
150161 int len = r - l + 1 ;
151- int p = log2 [r - l + 1 ];
162+ int p = log2 [len ];
152163 long leftInterval = dp [p ][l ];
153164 long rightInterval = dp [p ][r - (1 << p ) + 1 ];
154165 if (leftInterval <= rightInterval ) {
@@ -160,7 +171,7 @@ private int minQueryIndex(int l, int r) {
160171
161172 private int maxQueryIndex (int l , int r ) {
162173 int len = r - l + 1 ;
163- int p = log2 [r - l + 1 ];
174+ int p = log2 [len ];
164175 long leftInterval = dp [p ][l ];
165176 long rightInterval = dp [p ][r - (1 << p ) + 1 ];
166177 if (leftInterval >= rightInterval ) {
@@ -184,14 +195,25 @@ private long sumQuery(int l, int r) {
184195 for (int p = P ; p >= 0 ; p --) {
185196 int rangeLength = r - l + 1 ;
186197 if ((1 << p ) <= rangeLength ) {
187- // System.out.printf("[%d, %d)\n", l, l + (1<<p));
188198 sum += dp [p ][l ];
189199 l += (1 << p );
190200 }
191201 }
192202 return sum ;
193203 }
194204
205+ private long multQuery (int l , int r ) {
206+ long result = 1 ;
207+ for (int p = P ; p >= 0 ; p --) {
208+ int rangeLength = r - l + 1 ;
209+ if ((1 << p ) <= rangeLength ) {
210+ result *= dp [p ][l ];
211+ l += (1 << p );
212+ }
213+ }
214+ return result ;
215+ }
216+
195217 // Do either a min, max or gcd query on the interval [l, r] in O(1).
196218 //
197219 // We can get O(1) query by finding the smallest power of 2 that fits within the interval length
@@ -201,7 +223,7 @@ private long sumQuery(int l, int r) {
201223 // wrong result since it is not an idempotent binary function.
202224 private long query (int l , int r , BinaryOperator <Long > fn ) {
203225 int len = r - l + 1 ;
204- int p = log2 [r - l + 1 ];
226+ int p = log2 [len ];
205227 return fn .apply (dp [p ][l ], dp [p ][r - (1 << p ) + 1 ]);
206228 }
207229
@@ -217,27 +239,16 @@ private static void example1() {
217239 // Initialize sparse table to do range minimum queries.
218240 SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .MIN );
219241
220- // Prints: "Min value between [2, 7] = -1"
221242 System .out .printf ("Min value between [2, 7] = %d\n " , sparseTable .query (2 , 7 ));
222-
223- // Prints: "Index of min value between [2, 7] = 5". Returns the leftmost index in the
224- // event that there are duplicates.
225- System .out .printf ("Index of min value between [2, 7] = %d\n " , sparseTable .queryIndex (2 , 7 ));
226243 }
227244
228245 private static void example2 () {
229246 long [] values = {4 , 2 , 3 , 7 , 1 , 5 , 3 , 3 , 9 , 6 , 7 , -1 , 4 };
230- System .out .println (values .length );
231247
232248 // Initialize sparse table to do range minimum queries.
233249 SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .MIN );
234250
235- // Prints: "Min value between [2, 7] = -1"
236251 System .out .printf ("Min value between [2, 7] = %d\n " , sparseTable .query (2 , 7 ));
237-
238- // Prints: "Index of min value between [2, 7] = 5". Returns the leftmost index in the
239- // event that there are duplicates.
240- // System.out.printf("Index of min value between [2, 7] = %d\n", sparseTable.queryIndex(2, 7));
241252 }
242253
243254 private static void example3 () {
@@ -247,11 +258,6 @@ private static void example3() {
247258 // Initialize sparse table to do range minimum queries.
248259 SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .SUM );
249260
250- // Prints: "Min value between [2, 7] = -1"
251261 System .out .printf ("Min value between [5, 17] = %d\n " , sparseTable .query (5 , 17 ));
252-
253- // Prints: "Index of min value between [5, 17] = 5". Returns the leftmost index in the
254- // event that there are duplicates.
255- // System.out.printf("Index of min value between [5, 17] = %d\n", sparseTable.queryIndex(2, 7));
256262 }
257263}
0 commit comments