@@ -38,6 +38,7 @@ public enum Operation {
38
38
MIN ,
39
39
MAX ,
40
40
SUM ,
41
+ MULT ,
41
42
GCD
42
43
};
43
44
@@ -47,6 +48,7 @@ public enum Operation {
47
48
private BinaryOperator <Long > sumFn = (a , b ) -> a + b ;
48
49
private BinaryOperator <Long > minFn = (a , b ) -> Math .min (a , b );
49
50
private BinaryOperator <Long > maxFn = (a , b ) -> Math .max (a , b );
51
+ private BinaryOperator <Long > multFn = (a , b ) -> a * b ;
50
52
private BinaryOperator <Long > gcdFn =
51
53
(a , b ) -> {
52
54
long gcd = a ;
@@ -106,6 +108,8 @@ private void init(long[] v) {
106
108
}
107
109
} else if (op == Operation .SUM ) {
108
110
dp [i ][j ] = sumFn .apply (leftInterval , rightInterval );
111
+ } else if (op == Operation .MULT ) {
112
+ dp [i ][j ] = multFn .apply (leftInterval , rightInterval );
109
113
} else if (op == Operation .GCD ) {
110
114
dp [i ][j ] = gcdFn .apply (leftInterval , rightInterval );
111
115
}
@@ -126,14 +130,21 @@ private void printTable() {
126
130
127
131
// Queries [l, r] for the operation set on this sparse table.
128
132
public long query (int l , int r ) {
133
+ // Fast queries types, O(1)
129
134
if (op == Operation .MIN ) {
130
135
return query (l , r , minFn );
131
136
} else if (op == Operation .MAX ) {
132
137
return query (l , r , maxFn );
133
138
} else if (op == Operation .GCD ) {
134
139
return query (l , r , gcdFn );
135
140
}
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
+ }
137
148
}
138
149
139
150
public int queryIndex (int l , int r ) {
@@ -148,7 +159,7 @@ public int queryIndex(int l, int r) {
148
159
149
160
private int minQueryIndex (int l , int r ) {
150
161
int len = r - l + 1 ;
151
- int p = log2 [r - l + 1 ];
162
+ int p = log2 [len ];
152
163
long leftInterval = dp [p ][l ];
153
164
long rightInterval = dp [p ][r - (1 << p ) + 1 ];
154
165
if (leftInterval <= rightInterval ) {
@@ -160,7 +171,7 @@ private int minQueryIndex(int l, int r) {
160
171
161
172
private int maxQueryIndex (int l , int r ) {
162
173
int len = r - l + 1 ;
163
- int p = log2 [r - l + 1 ];
174
+ int p = log2 [len ];
164
175
long leftInterval = dp [p ][l ];
165
176
long rightInterval = dp [p ][r - (1 << p ) + 1 ];
166
177
if (leftInterval >= rightInterval ) {
@@ -184,14 +195,25 @@ private long sumQuery(int l, int r) {
184
195
for (int p = P ; p >= 0 ; p --) {
185
196
int rangeLength = r - l + 1 ;
186
197
if ((1 << p ) <= rangeLength ) {
187
- // System.out.printf("[%d, %d)\n", l, l + (1<<p));
188
198
sum += dp [p ][l ];
189
199
l += (1 << p );
190
200
}
191
201
}
192
202
return sum ;
193
203
}
194
204
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
+
195
217
// Do either a min, max or gcd query on the interval [l, r] in O(1).
196
218
//
197
219
// 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) {
201
223
// wrong result since it is not an idempotent binary function.
202
224
private long query (int l , int r , BinaryOperator <Long > fn ) {
203
225
int len = r - l + 1 ;
204
- int p = log2 [r - l + 1 ];
226
+ int p = log2 [len ];
205
227
return fn .apply (dp [p ][l ], dp [p ][r - (1 << p ) + 1 ]);
206
228
}
207
229
@@ -217,27 +239,16 @@ private static void example1() {
217
239
// Initialize sparse table to do range minimum queries.
218
240
SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .MIN );
219
241
220
- // Prints: "Min value between [2, 7] = -1"
221
242
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 ));
226
243
}
227
244
228
245
private static void example2 () {
229
246
long [] values = {4 , 2 , 3 , 7 , 1 , 5 , 3 , 3 , 9 , 6 , 7 , -1 , 4 };
230
- System .out .println (values .length );
231
247
232
248
// Initialize sparse table to do range minimum queries.
233
249
SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .MIN );
234
250
235
- // Prints: "Min value between [2, 7] = -1"
236
251
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));
241
252
}
242
253
243
254
private static void example3 () {
@@ -247,11 +258,6 @@ private static void example3() {
247
258
// Initialize sparse table to do range minimum queries.
248
259
SparseTable sparseTable = new SparseTable (values , SparseTable .Operation .SUM );
249
260
250
- // Prints: "Min value between [2, 7] = -1"
251
261
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));
256
262
}
257
263
}
0 commit comments