@@ -43,9 +43,6 @@ public enum Operation {
43
43
return Math .abs (gcd );
44
44
};
45
45
46
-
47
- // Supply an array of values and an associative binary function. The function
48
- // is usually min, max sum, gcd, etc... see pre-made ones below.
49
46
public SparseTable (int [] v , Operation op ) {
50
47
this .op = op ;
51
48
init (v );
@@ -85,53 +82,85 @@ private void init(int[] v) {
85
82
print (t );
86
83
}
87
84
85
+ // Queries [l, r] for the operation set on this Sparse table.
88
86
public int query (int l , int r ) {
89
87
if (op == Operation .MIN ) {
90
- return minQuery (l , r );
88
+ return query (l , r , minFn );
91
89
} else if (op == Operation .MAX ) {
92
- return maxQuery (l , r );
90
+ return query (l , r , maxFn );
93
91
}
92
+ // TODO(william): add query for gcd
94
93
return sumQuery (l , r );
95
94
}
96
95
97
- // Do sum query [l, r] in O(lg(n))
96
+ // Do sum query [l, r] in O(lg(n)). Does a cascading query which shrinks the left endpoint
97
+ // while summing over all the intervals which are powers of 2 between [l, r].
98
+ // TODO(william): use longs?
98
99
public int sumQuery (int l , int r ) {
99
100
int sum = 0 ;
100
101
for (int p = P ; p >= 0 ; p --) {
101
- // System.out.println(l + " " + r);
102
102
int rangeLength = r - l + 1 ;
103
103
if ((1 << p ) <= rangeLength ) {
104
+ // System.out.printf("power = 2^%d = %d, l = %d, value = %d\n", p, 1<<p, l, t[p][l]);
104
105
sum += t [p ][l ];
105
106
l += (1 << p );
106
107
}
107
108
}
108
109
return sum ;
109
110
}
110
111
111
- // Do min query [l, r] in O(1)
112
- private int minQuery (int l , int r ) {
112
+ // Do either a min, max or gcd query on the interval [l, r] in O(1).
113
+ //
114
+ // We can get O(1) query by finding the smallest power of 2 that fits within the interval length
115
+ // which we'll call k. Then we can query the intervals [l, l+k] and [r-k+1, r] (which likely
116
+ // overlap) and apply the function again. Some functions (like min and max) don't care about
117
+ // overlapping intervals so this trick works, but for a function like sum this would return the
118
+ // wrong result.
119
+ private int query (int l , int r , BinaryOperator <Integer > fn ) {
120
+ int len = r - l + 1 ;
113
121
int p = log2 [r - l + 1 ];
114
- return Math . min (t [p ][l ], t [p ][r - (1 << p ) + 1 ]);
122
+ return fn . apply (t [p ][l ], t [p ][r - (1 << p ) + 1 ]);
115
123
}
116
124
117
- // Do max query [l, r] in O(1)
118
- private int maxQuery (int l , int r ) {
119
- int p = log2 [r - l + 1 ];
120
- return Math .max (t [p ][l ], t [p ][r - (1 << p ) + 1 ]);
121
- }
122
-
123
- private void print (int [][] t ) {
124
- for (int [] r : t ) {
125
- System .out .println (java .util .Arrays .toString (r ));
125
+ private static void print (int [][] t ) {
126
+ for (int i = 0 ; i < t .length ; i ++) {
127
+ for (int j = 0 ; j < t [0 ].length ; j ++) {
128
+ System .out .printf ("%3d," , t [i ][j ]);
129
+ }
130
+ System .out .println ();
126
131
}
127
132
System .out .println ();
128
133
}
129
134
130
135
public static void main (String [] args ) {
131
- int [] v = {1 ,8 ,5 ,6 ,7 ,2 ,7 ,1 ,8 ,5 ,6 ,7 ,2 ,4 ,3 };
132
- System .out .println (v .length );
133
- SparseTable st = new SparseTable (v , Operation .MIN );
136
+ int [] v = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 };
137
+ SparseTable st = new SparseTable (v , Operation .SUM );
138
+ System .out .println (st .query (1 , 7 ));
139
+ simpleTest ();
140
+ }
141
+
142
+ private static void simpleTest () {
143
+ int [] v = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 };
144
+ SparseTable st = new SparseTable (v , Operation .SUM );
145
+ for (int i = 0 ; i < v .length ; i ++) {
146
+ for (int j = i ; j < v .length ; j ++) {
147
+ int trueSum = 0 ;
148
+ for (int k = i ; k <= j ; k ++) {
149
+ trueSum += v [k ];
150
+ }
151
+ if (st .query (i , j ) != trueSum ) {
152
+ System .out .printf ("Ooopse, got %d instead of %d!\n " , st .query (i , j ), trueSum );
153
+ }
154
+ }
155
+ }
134
156
}
135
157
136
158
}
137
159
160
+
161
+
162
+
163
+
164
+
165
+
166
+
0 commit comments