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