competitive_library/structure/
disjoint_sparse_table.rs1use std::ops::Range;
2
3pub trait SemiGroup {
4 type T: Clone;
5 fn operate(a: &Self::T, b: &Self::T) -> Self::T;
6}
7
8pub struct Add {}
9impl SemiGroup for Add {
10 type T = i64;
11
12 fn operate(a: &Self::T, b: &Self::T) -> Self::T {
13 *a + *b
14 }
15}
16
17#[derive(Debug)]
18pub struct DisjointSparseTable<S: SemiGroup> {
19 pub table: Vec<Vec<S::T>>,
20}
21
22impl<S: SemiGroup> DisjointSparseTable<S> {
23 #[inline]
24 pub fn new(v: &[S::T]) -> Self {
25 let size = (32 - (v.len() as u32).saturating_sub(1).leading_zeros()) as usize;
26 let mut table = vec![v.to_vec()];
27
28 (1..size).for_each(|i| {
29 let mut tmp = v.to_vec();
30
31 let span = 2i64.pow(i as u32) as usize;
32
33 (0..v.len().div_ceil(span * 2)).for_each(|j| {
34 let start = span * 2 * j + span;
35
36 (0..span - 1)
37 .map(|k| start - 2 - k)
38 .filter(|&k| k + 1 < v.len())
39 .for_each(|k| {
40 tmp[k] = S::operate(&tmp[k], &tmp[k + 1]);
41 });
42
43 (0..span - 1)
44 .map(|k| k + start + 1)
45 .filter(|&k| k < v.len())
46 .for_each(|k| {
47 tmp[k] = S::operate(&tmp[k], &tmp[k - 1]);
48 });
49 });
50 table.push(tmp);
51 });
52
53 DisjointSparseTable { table }
54 }
55
56 #[inline]
57 pub fn fold(&self, range: Range<usize>) -> S::T {
58 if range.len() == 1 {
59 return self.table[0][range.start].clone();
60 }
61 let h = (32 - ((range.start ^ (range.end - 1)) as u32).leading_zeros()) as usize - 1;
62 S::operate(&self.table[h][range.start], &self.table[h][range.end - 1])
63 }
64}
65
66#[cfg(test)]
67mod tests {
68
69 use super::*;
70
71 #[test]
72 fn test_disjoint_sparse_table() {
73 let a = DisjointSparseTable::<Add>::new(&[2, 10, 1, 100]);
74 for &(l, r, ans) in [
75 (0, 1, 2),
76 (0, 2, 12),
77 (0, 3, 13),
78 (0, 4, 113),
79 (1, 2, 10),
80 (1, 3, 11),
81 (1, 4, 111),
82 (2, 3, 1),
83 (2, 4, 101),
84 (3, 4, 100),
85 ]
86 .iter()
87 {
88 assert_eq!(a.fold(l..r), ans);
89 }
90 }
91
92 #[test]
93 fn test_library_checker_sample() {
94 let a = DisjointSparseTable::<Add>::new(&[1, 10, 100, 1000, 10000]);
95 for &(l, r, ans) in [
96 (2, 3, 100),
97 (0, 3, 111),
98 (2, 5, 11100),
99 (3, 4, 1000),
100 (0, 5, 11111),
101 ]
102 .iter()
103 {
104 assert_eq!(a.fold(l..r), ans);
105 }
106 }
107}