Skip to main content

nekolib/ds/
disjoint_sparse_table.rs

1//! disjoint sparse table。
2
3use super::super::traits::binop;
4use super::super::traits::fold;
5use super::super::utils::buf_range;
6
7use std::convert::From;
8use std::ops::{Index, Range, RangeBounds};
9
10use binop::Monoid;
11use buf_range::bounds_within;
12use fold::Fold;
13
14/// disjoint sparse table。
15///
16/// 要素数 $n$ の配列の任意の区間について、モノイド積の値を計算できる。
17/// 値の更新はできない。
18/// 半群を返すことにしてもよいが、要検討。
19///
20/// # Idea
21/// 各 $k$ ($1\\le k\< \\log\_2(n)$) について、区間
22/// $[i\\cdot 2\^k-j, i\\cdot 2\^k)$ および $[i\\cdot 2\^k, i\\cdot 2\^k+j)$
23/// ($2\\le j\\le 2\^k$、$i$ は区間の終端が $n$ 以下になる各奇数)
24/// におけるモノイド積を予め計算しておく。
25/// 任意の区間は、上記の区間を高々 $2$ つ合わせることで表現できる。
26///
27/// # Implementation notes
28/// 前処理では、異なる段で同じ区間のモノイド積を複数回計算するのを避けるための工夫をしている。
29/// その処理のオーバーヘッドにより、モノイド積のコストが高くない場合は、
30/// 毎回計算する方が高速かもしれない。クエリ処理についても同様の工夫をしている。
31///
32/// # Complexity
33/// |演算|時間計算量|
34/// |---|---|
35/// |`from`|$\\Theta(n\\log(n))$|
36/// |`fold`|$\\Theta(1)$|
37///
38/// # Precise analysis
39/// 前処理におけるモノイド積の計算回数は以下の値で上から抑えられる。
40/// $$ n\\cdot\\lceil{\\log\_2(n)-3}\\rceil + 2\\cdot\\lceil{\\log\_2(n)}\\rceil + 2. $$
41///
42/// これは、$n = 1000$ で $7022$ であり、
43/// [Secret](http://s3-ap-northeast-1.amazonaws.com/data.cms.ioi-jp.org/open-2014/2014-open-d2-secret.pdf)
44/// の「$n = 1000$ でクエリ $8000$ 回以下」に余裕を持って間に合う。
45///
46/// クエリ処理の際には、
47/// 与えられた区間が前処理で計算した区間であるか、長さが $1$ 以下の場合は、
48/// 新たにモノイド積は計算せずに答えを返す。
49/// そうでない場合はちょうど $1$ 回のモノイド積を計算する。
50///
51/// ## More precise analysis
52///
53/// 前処理の実際の計算回数は、以下のコードにより $O(\\log(n))$ 時間で計算できるはず。
54/// コード長が長いので隔離したいかも。
55/// ```
56/// /// 要素数 `n` での前処理における計算回数を返す。
57/// fn count(n: usize) -> usize {
58///     if n <= 2 {
59///         return 0;
60///     }
61///     g(n - 1)
62///         + if n.is_power_of_two() {
63///             n.trailing_zeros() as usize
64///         } else {
65///             n.next_power_of_two() / 2
66///         }
67///         - 1
68/// }
69///
70/// assert_eq!(count(3), 1);
71/// assert_eq!(count(10), 14);
72/// assert_eq!(count(1000), 7008);
73/// assert_eq!(count(1_000_000), 16_980_635);
74///
75/// /// 各段における寄与分の和を返す。
76/// fn g(n: usize) -> usize {
77///     (0..)
78///         .take_while(|&k| n >= 2_usize.pow(k + 1))
79///         .map(|k| f(k, n - 2_usize.pow(k + 1)))
80///         .sum()
81/// }
82///
83/// /// k 段目における寄与分を返す。
84/// fn f(k: u32, n: usize) -> usize {
85///     let p = 2_usize.pow(k);
86///     n / (2 * p) * p
87///         + if n / p % 2 == 1 { n % p + 1 } else { 0 }
88///         + (n + 1) / (2 * p) * (p - 1)
89/// }
90/// ```
91///
92/// # Examples
93/// ```
94/// use nekolib::ds::DisjointSparseTable;
95/// use nekolib::traits::Fold;
96/// use nekolib::utils::OpRollHash;
97///
98/// let op_rh = OpRollHash::<998244353>::default();
99/// let value_of = |s| op_rh.value_of(s);
100///
101/// let base: Vec<_> = ["abra", "cad", "abra"].iter().map(|s| value_of(s)).collect();
102/// let dst: DisjointSparseTable<_> = (base, op_rh).into();
103/// assert_eq!(dst.fold(1..=2), value_of("cadabra"));
104/// assert_eq!(dst.fold(..), value_of("abracadabra"));
105/// ```
106pub struct DisjointSparseTable<M: Monoid> {
107    buf: Vec<Vec<M::Set>>,
108    monoid: M,
109}
110
111impl<M, B> Fold<B> for DisjointSparseTable<M>
112where
113    M: Monoid,
114    M::Set: Clone,
115    B: RangeBounds<usize>,
116{
117    type Output = M;
118    fn fold(&self, b: B) -> M::Set {
119        let Range { start, end } = bounds_within(b, self.buf[0].len());
120        if start >= end {
121            return self.monoid.id();
122        }
123        let len = end - start;
124        let end = end - 1;
125        if start == end {
126            return self.buf[0][start].clone();
127        }
128        let row = ((start ^ end) + 1).next_power_of_two().trailing_zeros() - 1;
129        let row_len = 1_usize << row;
130        let row = row as usize;
131
132        if len <= 2 * row_len && row + 1 < self.buf.len() {
133            if start.is_power_of_two() && end >> (row + 1) == 1 {
134                return self.buf[row + 1][end].clone();
135            }
136            if (end + 1).is_power_of_two() && start >> (row + 1) == 0 {
137                return self.buf[row + 1][start].clone();
138            }
139        }
140
141        self.monoid.op(self.buf[row][start].clone(), self.buf[row][end].clone())
142    }
143}
144
145impl<M> From<Vec<M::Set>> for DisjointSparseTable<M>
146where
147    M: Monoid + Default,
148    M::Set: Clone,
149{
150    fn from(base: Vec<M::Set>) -> Self { Self::from((base, M::default())) }
151}
152
153impl<M> From<(Vec<M::Set>, M)> for DisjointSparseTable<M>
154where
155    M: Monoid,
156    M::Set: Clone,
157{
158    fn from((base, monoid): (Vec<M::Set>, M)) -> Self {
159        let len = base.len();
160
161        let height = len.next_power_of_two().trailing_zeros().max(1) as usize;
162        let mut buf = vec![base; height];
163
164        for i in 1..height {
165            let w = 1 << i;
166            for j in (1..).step_by(2).take_while(|&j| j * w <= len) {
167                let mid = j * w;
168                for r in (1..w).take_while(|r| mid + r < len) {
169                    buf[i][mid + r] = monoid.op(
170                        buf[i][mid + r - 1].clone(),
171                        buf[0][mid + r].clone(),
172                    );
173                }
174            }
175        }
176
177        for i in 1..height {
178            let w = 1 << i;
179            for j in (1..).step_by(2).take_while(|&j| j * w <= len) {
180                let mid = j * w - 1;
181                for l in 1..w {
182                    buf[i][mid - l] = if mid > l && (l + 1).is_power_of_two() {
183                        let ei = (mid - l).trailing_zeros() as usize;
184                        let ej = mid;
185                        buf[ei][ej].clone()
186                    } else {
187                        monoid.op(
188                            buf[0][mid - l].clone(),
189                            buf[i][mid - l + 1].clone(),
190                        )
191                    };
192                }
193            }
194        }
195        Self { buf, monoid }
196    }
197}
198
199impl<M> Index<usize> for DisjointSparseTable<M>
200where
201    M: Monoid,
202    M::Set: Clone,
203{
204    type Output = M::Set;
205    fn index(&self, i: usize) -> &Self::Output { &self.buf[0][i] }
206}