competitive_library/structure/
sparse_table.rs

1//! SparseTable
2//! 冪等半群列にたいして区間[l,r) の結果を戻す
3//! 構築 O(NlogN) クエリO(1)
4//! min, max, gcd, lcm 等
5
6use std::ops::Range;
7
8/// 冪等半群
9pub trait Band {
10    type T: Clone;
11    fn operate(a: &Self::T, b: &Self::T) -> Self::T;
12}
13
14/// 最小値
15pub struct Min {}
16impl Band for Min {
17    type T = i64;
18
19    fn operate(a: &Self::T, b: &Self::T) -> Self::T {
20        *a.min(b)
21    }
22}
23
24/// SparseTable
25pub struct SparseTable<B: Band> {
26    table: Vec<Vec<B::T>>,
27}
28
29impl<B: Band> SparseTable<B> {
30    /// O(NlogN)
31    pub fn new(v: &[B::T]) -> Self {
32        let mut table = vec![v.to_vec()];
33
34        for i in 1..64 - v.len().leading_zeros() as usize {
35            let mut tmp = vec![];
36            for j in 0..=v.len() - (1 << i) {
37                tmp.push(B::operate(
38                    &table[i - 1][j],
39                    &table[i - 1][j + (1 << (i - 1))],
40                ));
41            }
42            table.push(tmp);
43        }
44
45        SparseTable { table }
46    }
47
48    /// [l,r)
49    /// O(1)
50    pub fn fold(&self, range: Range<usize>) -> B::T {
51        let i = 64 - (range.end - range.start).leading_zeros() as usize - 1;
52        B::operate(
53            &self.table[i][range.start],
54            &self.table[i][range.end - (1 << i)],
55        )
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    #[test]
63    fn test_sparse_table() {
64        let a = SparseTable::<Min>::new(&[2, 10, 1, 100]);
65        for (l, r, ans) in [
66            (0, 1, 2),
67            (0, 2, 2),
68            (0, 3, 1),
69            (0, 4, 1),
70            (1, 2, 10),
71            (1, 3, 1),
72            (1, 4, 1),
73            (2, 3, 1),
74            (2, 4, 1),
75            (3, 4, 100),
76        ]
77        .iter()
78        {
79            assert_eq!(a.fold(*l..*r), *ans);
80        }
81    }
82}