competitive/algorithm/
sqrt_decomposition.rs1#![allow(clippy::type_complexity)]
2
3use super::{Magma, Monoid, RangeBoundsExt, Unital};
4use std::ops::RangeBounds;
5
6pub trait SqrtDecomposition: Sized {
7 type M: Monoid;
8 type B;
9 fn bucket(bsize: usize) -> Self::B;
10 fn update_bucket(bucket: &mut Self::B, x: &<Self::M as Magma>::T);
11 fn update_cell(
12 bucket: &mut Self::B,
13 cell: &mut <Self::M as Magma>::T,
14 x: &<Self::M as Magma>::T,
15 );
16 fn fold_bucket(bucket: &Self::B) -> <Self::M as Magma>::T;
17 fn fold_cell(bucket: &Self::B, cell: &<Self::M as Magma>::T) -> <Self::M as Magma>::T;
18 fn sqrt_decomposition(n: usize, bucket_size: usize) -> SqrtDecompositionBuckets<Self> {
19 let mut buckets = vec![];
20 for l in (0..n).step_by(bucket_size) {
21 let bsize = (l + bucket_size).min(n) - l;
22 let x = Self::bucket(bsize);
23 buckets.push((vec![Self::M::unit(); bsize], x));
24 }
25 SqrtDecompositionBuckets {
26 n,
27 bucket_size,
28 buckets,
29 _marker: std::marker::PhantomData,
30 }
31 }
32}
33
34pub struct SqrtDecompositionBuckets<S>
35where
36 S: SqrtDecomposition,
37{
38 n: usize,
39 bucket_size: usize,
40 buckets: Vec<(Vec<<S::M as Magma>::T>, S::B)>,
41 _marker: std::marker::PhantomData<fn() -> S>,
42}
43impl<S> SqrtDecompositionBuckets<S>
44where
45 S: SqrtDecomposition,
46{
47 pub fn update_cell(&mut self, i: usize, x: <S::M as Magma>::T) {
48 let (cells, bucket) = &mut self.buckets[i / self.bucket_size];
49 let j = i % self.bucket_size;
50 S::update_cell(bucket, &mut cells[j], &x);
51 }
52 pub fn update<R>(&mut self, range: R, x: <S::M as Magma>::T)
53 where
54 R: RangeBounds<usize>,
55 {
56 let range = range.to_range_bounded(0, self.n).expect("invalid range");
57 for (i, (cells, bucket)) in self.buckets.iter_mut().enumerate() {
58 let s = i * self.bucket_size;
59 let t = s + cells.len();
60 if t <= range.start || range.end <= s {
61 } else if range.start <= s && t <= range.end {
62 S::update_bucket(bucket, &x);
63 } else {
64 for cell in &mut cells[range.start.max(s) - s..range.end.min(t) - s] {
65 S::update_cell(bucket, cell, &x);
66 }
67 }
68 }
69 }
70 pub fn get(&self, i: usize) -> <S::M as Magma>::T {
71 let (cells, bucket) = &self.buckets[i / self.bucket_size];
72 let j = i % self.bucket_size;
73 S::fold_cell(bucket, &cells[j])
74 }
75 pub fn fold<R>(&self, range: R) -> <S::M as Magma>::T
76 where
77 R: RangeBounds<usize>,
78 {
79 let range = range.to_range_bounded(0, self.n).expect("invalid range");
80 let mut res = S::M::unit();
81 for (i, (cells, bucket)) in self.buckets.iter().enumerate() {
82 let s = i * self.bucket_size;
83 let t = s + cells.len();
84 if t <= range.start || range.end <= s {
85 } else if range.start <= s && t <= range.end {
86 <S::M as Magma>::operate_assign(&mut res, &S::fold_bucket(bucket));
87 } else {
88 for cell in &cells[range.start.max(s) - s..range.end.min(t) - s] {
89 <S::M as Magma>::operate_assign(&mut res, &S::fold_cell(bucket, cell));
90 }
91 }
92 }
93 res
94 }
95}