1#[inline(always)]
2fn flog2(v: usize) -> usize {
3 v.ilog2() as usize
4}
5
6pub trait Rmq {
7 fn rmq(&self, i: usize, j: usize) -> Option<usize>;
8}
9
10pub struct Sparse {
11 lgn: usize,
12 table: Vec<usize>,
13}
14
15impl Sparse {
16 pub fn new(array: &[usize]) -> Self {
17 let n = array.len();
18 let lgn = flog2(n) + 1;
19 let mut table: Vec<usize> = vec![0; lgn * n];
20
21 for j in 0..n {
22 table[j * lgn] = array[j];
23 }
24
25 for i in 1..lgn {
26 for j in 0..=(n - (1 << i)) {
27 table[j * lgn + i] = std::cmp::min(
28 table[j * lgn + i - 1],
29 table[(j + (1 << (i - 1))) * lgn + i - 1],
30 );
31 }
32 }
33
34 Sparse { lgn, table }
35 }
36}
37
38impl Rmq for Sparse {
39 fn rmq(&self, i: usize, j: usize) -> Option<usize> {
40 if i >= j {
41 return None;
42 }
43
44 let k = flog2(j - i);
45 Some(std::cmp::min(
46 self.table[i * self.lgn + k],
47 self.table[(j - (1 << k)) * self.lgn + k],
48 ))
49 }
50}
51
52struct Matrix {
54 n: usize,
55 table: Vec<usize>,
56}
57
58impl Matrix {
59 pub fn new(n: usize) -> Matrix {
60 let table = vec![0; n * n];
61 Matrix { n, table }
62 }
63
64 fn flat_index(&self, i: usize, j: usize) -> usize {
65 debug_assert!(i < self.n && j < self.n);
66 i * self.n + j
67 }
68}
69
70impl std::ops::Index<(usize, usize)> for Matrix {
71 type Output = usize;
72 fn index(&self, index: (usize, usize)) -> &Self::Output {
73 let (i, j) = index;
74 &self.table[self.flat_index(i, j)]
75 }
76}
77
78impl std::ops::IndexMut<(usize, usize)> for Matrix {
79 fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
80 let (i, j) = index;
81 let flat_idx = self.flat_index(i, j);
82 &mut self.table[flat_idx]
83 }
84}
85
86#[derive(Clone)]
88struct UTTable {
89 n: usize,
90 table: Vec<usize>,
91}
92
93impl UTTable {
94 pub fn new(n: usize) -> UTTable {
95 let table: Vec<usize> = vec![0; n * (n + 1) / 2];
96 UTTable { n, table }
97 }
98
99 fn flat_index(&self, i: usize, j: usize) -> usize {
100 debug_assert!(i < self.n);
101 debug_assert!(i < j && j <= self.n);
102 let k = self.n - i - 1;
103 k * (k + 1) / 2 + j - i - 1
104 }
105}
106
107impl std::ops::Index<(usize, usize)> for UTTable {
108 type Output = usize;
109 fn index(&self, index: (usize, usize)) -> &Self::Output {
110 let (i, j) = index;
111 &self.table[self.flat_index(i, j)]
112 }
113}
114
115impl std::ops::IndexMut<(usize, usize)> for UTTable {
116 fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
117 let (i, j) = index;
118 let flat_idx = self.flat_index(i, j);
119 &mut self.table[flat_idx]
120 }
121}
122
123#[derive(Clone)]
125struct TabulatedQuery {
126 tbl: UTTable,
127}
128
129impl Rmq for TabulatedQuery {
130 fn rmq(&self, i: usize, j: usize) -> Option<usize> {
131 if i < j {
132 Some(self.tbl[(i, j)])
133 } else {
134 None
135 }
136 }
137}
138
139impl TabulatedQuery {
140 pub fn new(x: &[usize]) -> Self {
141 let mut tbl = UTTable::new(x.len());
142 for i in 0..x.len() {
143 tbl[(i, i + 1)] = i;
144 }
145 for i in 0..x.len() - 1 {
146 for j in i + 2..x.len() + 1 {
147 tbl[(i, j)] = if x[tbl[(i, j - 1)]] <= x[j - 1] {
149 tbl[(i, j - 1)]
150 } else {
151 j - 1
152 };
153 }
154 }
155 TabulatedQuery { tbl }
156 }
157}
158
159#[derive(Clone, Copy)]
160struct BlockSize(pub usize);
161
162#[derive(PartialEq, PartialOrd)]
163struct BlockIdx(pub usize);
164
165fn block_size(n: usize) -> BlockSize {
166 BlockSize(flog2(n) + 1)
167}
168
169fn round_down(i: usize, bs: BlockSize) -> (BlockIdx, usize) {
170 let BlockSize(bs) = bs;
171 let r = i / bs;
172 (BlockIdx(r), r * bs)
173}
174fn round_up(i: usize, bs: BlockSize) -> (BlockIdx, usize) {
175 let BlockSize(bs) = bs;
176 let r = (i + bs - 1) / bs;
177 (BlockIdx(r), r * bs)
178}
179
180fn reduce_array(x: &[usize], block_size: BlockSize) -> Vec<usize> {
183 let BlockSize(bs) = block_size;
184 x.chunks(bs)
185 .map(|block| *block.iter().min().unwrap())
186 .collect()
187}
188
189fn tabulate_ballot_numbers(b: usize) -> Matrix {
192 let mut ballot = Matrix::new(b + 1);
193 for q in 0..=b {
194 ballot[(0, q)] = 1
195 }
196 for q in 1..=b {
197 for p in 1..=q {
198 ballot[(p, q)] = ballot[(p - 1, q)] + ballot[(p, q - 1)]
199 }
200 }
201 ballot
202}
203
204fn block_type(block: &[usize], b: usize, stack: &mut [i64], ballot: &Matrix) -> usize {
209 let mut num = 0;
210 let mut top = 0;
211 stack[top] = i64::MIN; for (i, &v) in block.iter().enumerate() {
214 let signed_v = v as i64;
215
216 let p = b - i;
220 while stack[top] > signed_v {
221 let q = b - (i - top);
223 num += ballot[(p - 1, q)];
224 top -= 1;
225 }
226
227 top += 1;
229 stack[top] = signed_v;
230 }
231
232 num
233}
234
235fn tabulate_blocks(x: &[usize], b: usize) -> (Vec<usize>, Vec<Option<TabulatedQuery>>) {
237 let no_blocks = (x.len() + b - 1) / b;
241
242 let ballot = tabulate_ballot_numbers(b);
243 let mut stack: Vec<i64> = vec![i64::MIN; b + 1];
244
245 let mut block_types = vec![0; no_blocks];
246 let mut block_tables = vec![None; ballot[(b, b)]];
247 for i in 0..no_blocks {
248 let begin = i * b;
249 let end = std::cmp::min(x.len(), begin + b);
254 let block = &x[begin..end];
255
256 let bt = block_type(block, b, &mut stack, &ballot);
257 block_types[i] = bt;
258 if block_tables[bt].is_none() {
259 block_tables[bt] = Some(TabulatedQuery::new(block));
260 }
261 }
262 (block_types, block_tables)
263}
264
265pub struct Tabulation<'a> {
266 x: &'a [usize],
267 block_size: BlockSize,
268 sparse: Sparse,
269 block_types: Vec<usize>,
270 block_tables: Vec<Option<TabulatedQuery>>,
271}
272
273impl<'a> Tabulation<'a> {
274 pub fn new(x: &'a [usize]) -> Self {
275 let n = x.len();
276 let BlockSize(b) = block_size(n);
277
278 let b = std::cmp::max(4, b / 4); let block_size = BlockSize(b);
281
282 let reduced_vals = reduce_array(x, block_size);
283 let (block_types, block_tables) = tabulate_blocks(x, b);
284
285 Tabulation {
286 x,
287 block_size,
288 sparse: Sparse::new(&reduced_vals),
289 block_types,
290 block_tables,
291 }
292 }
293
294 fn block_rmq(&self, i: usize, j: usize) -> Option<usize> {
295 if j <= i {
296 return None;
297 }
298
299 let BlockSize(bs) = self.block_size;
300 let block_index = i / bs; let block_begin = block_index * bs; let btype = self.block_types[block_index];
305 let tbl = self.block_tables[btype].as_ref().unwrap();
307
308 let rmq_idx = tbl.rmq(i - block_begin, j - block_begin)? + block_begin;
310 Some(self.x[rmq_idx])
311 }
312}
313
314fn lift_op<T: Copy>(f: impl Fn(T, T) -> T) -> impl Fn(Option<T>, Option<T>) -> Option<T> {
315 move |a, b| match (a, b) {
316 (None, None) => None,
317 (Some(_), None) => a,
318 (None, Some(_)) => b,
319 (Some(a), Some(b)) => Some(f(a, b)),
320 }
321}
322
323impl<'a> Rmq for Tabulation<'a> {
324 fn rmq(&self, i: usize, j: usize) -> Option<usize> {
325 let BlockSize(bs) = self.block_size;
326 let bi = BlockIdx(i / bs);
327 let (sparse_bi, ii) = round_up(i, BlockSize(bs));
330 let (bj, jj) = round_down(j, BlockSize(bs));
332
333 if bi < bj {
334 let p1 = self.block_rmq(i, ii);
335 let (BlockIdx(sparse_bi), BlockIdx(bj)) = (sparse_bi, bj);
336 let p2 = self.sparse.rmq(sparse_bi, bj);
337 let p3 = self.block_rmq(jj, j);
338 let min = lift_op(std::cmp::min);
339 Some(min(min(p1, p2), p3)?)
340 } else {
341 Some(self.block_rmq(i, j)?)
342 }
343 }
344}
345
346#[cfg(test)]
347mod tests;