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
use std::ops::{Range, RangeBounds};

use usize_bounds::UsizeBounds;

pub struct SqrtBucket<T, S, Ff, Fr, Fq> {
    buf: Vec<T>,
    summary: Vec<S>,
    force: Ff,
    reduce: Fr,
    query: Fq,
    bucket_size: usize,
}

pub enum BucketBorrow<'a, T, S> {
    Slice(&'a mut [T]),
    Summary(&'a mut S),
}

impl<T, S, Ff, Fr, Fq> SqrtBucket<T, S, Ff, Fr, Fq>
where
    Fr: FnMut(&[T]) -> S,
    Ff: FnMut(&S, &mut [T]),
{
    pub fn new(buf: Vec<T>, force: Ff, reduce: Fr, query: Fq) -> Self {
        Self::new_with_bucket_size(buf, force, reduce, query, 384)
    }

    pub fn new_with_bucket_size(
        buf: Vec<T>,
        force: Ff,
        mut reduce: Fr,
        query: Fq,
        bucket_size: usize,
    ) -> Self {
        let summary: Vec<S> =
            buf.chunks(bucket_size).map(&mut reduce).collect();
        Self { buf, summary, force, reduce, query, bucket_size }
    }

    pub fn query<Q, B, R>(&mut self, range: B, args: Q) -> R
    where
        B: RangeBounds<usize>,
        Fq: for<'a> FnMut(&mut [BucketBorrow<'a, T, S>], Q) -> R,
    {
        let n = self.buf.len();
        let b = self.bucket_size;
        let Range { start, end } = range.to_range(n);

        let mut borrowed = vec![];
        let mut affected = vec![];
        for ((l, chunk_i), summary_i) in
            (0..n).step_by(b).zip(self.buf.chunks_mut(b)).zip(&mut self.summary)
        {
            let i = l / b;
            let r = n.min(l + b);
            if r <= start {
                continue;
            }
            if end <= l {
                break;
            }
            if start <= l && r <= end {
                borrowed.push(BucketBorrow::Summary(summary_i));
            } else {
                (self.force)(summary_i, chunk_i);
                affected.push((i, (l, r)));
                let jl = l.max(start) - l;
                let jr = r.min(end) - l;
                borrowed.push(BucketBorrow::Slice(&mut chunk_i[jl..jr]));
            }
        }
        let res = (self.query)(&mut borrowed, args);
        for (i, (l, r)) in affected {
            self.summary[i] = (self.reduce)(&mut self.buf[l..r]);
        }
        res
    }
}

// TODO: doc (cf. <https://atcoder.jp/contests/abc322/submissions/53952026>)