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
//! 尺取り法。

use super::super::traits::elastic_slice;

use elastic_slice::{ElasticSlice, ExpandBack, ShrinkFront, SliceHash};

/// 尺取り法で、各始端に対して境界を探す。
///
/// スライスと述語を引数に取り、スライスの各始端 $l$ に対して $r\_l$ を求める。
/// $r\_l$ は、以下の両方を満たす $r < n$ が存在すればその $r$、存在しなければ $n$ である。
/// $$ P(h([l, r))) \\text{ and } \\lnot P(h([l, r+1))). $$
///
/// ここで、$P$ は `pred`、$h([l, r))$ は `slice.start() == l`, `slice.end() == r`
/// における `slice.hash(())` によって計算される。
///
/// # Requirements
/// 各始端 $l$ に対して、$\\lnot P(h([l, m\_l)))$ なる $m\_l$
/// が存在するとき、次の二つが成り立つ。
/// - ${}^\\forall i\\in [l, m\_l)$ について $P(h([l, i)))$
/// - ${}^\\forall i\\in (m\_l, n)$ について $\\lnot P(h([l, i)))$
///
/// また、空区間に対しては $P$ は真を返す必要がある[^1]。
///
/// [^1]: そうでないと、返り値が定義しにくいためである。
/// $l-1$ や $-1$ が返り値として挙げられるが、後者では
/// `1_usize.wrapping_neg()` を使う必要がある上、大小関係がややこしくなり厄介。
///
/// # Complexity
/// `expand_back` および `shrink_front` の呼び出しを高々 $n$ 回、
/// `pred` の呼び出しを高々 $2n$ 回行う。
///
/// # Suggestions
/// [Examples] を見ての通り、構造体の宣言が大袈裟に感じられる。
/// 一方で、クロージャを渡すような設計でも綺麗にはならないと思われる。
///
/// 構造体を作るのが冗長に感じる程度の場合には、
/// これを使わずにインラインで書いてしまう方が楽そうに見えてしまう。
///
/// [Examples]: #examples
///
/// # Examples
/// ```
/// use nekolib::traits::{ElasticSlice, ExpandBack, ShrinkFront, SliceHash};
/// use nekolib::algo::window_bisect;
///
/// struct RangeSum {
///     buf: Vec<i32>,
///     start: usize,
///     end: usize,
///     sum: i32,
/// }
///
/// impl From<Vec<i32>> for RangeSum {
///     fn from(buf: Vec<i32>) -> Self {
///         Self { buf, start: 0, end: 0, sum: 0 }
///     }
/// }
///
/// impl ElasticSlice for RangeSum {
///     fn reset(&mut self) {
///         self.start = 0;
///         self.end = 0;
///         self.sum = 0;
///     }
///     fn full_len(&self) -> usize { self.buf.len() }
///     fn start(&self) -> usize { self.start }
///     fn end(&self) -> usize { self.end }
/// }
///
/// impl SliceHash for RangeSum {
///     type Salt = ();
///     type Hashed = i32;
///     fn hash(&self, _: ()) -> i32 { self.sum }
/// }
///
/// impl ExpandBack for RangeSum {
///     fn expand_back(&mut self) {
///         self.sum += self.buf[self.end];
///         self.end += 1;
///     }
/// }
///
/// impl ShrinkFront for RangeSum {
///     fn shrink_front(&mut self) {
///         self.sum -= self.buf[self.start];
///         self.start += 1;
///     }
/// }
///
/// let rs: RangeSum = vec![1, 4, 1, 4, 2, 1, 3, 5, 6].into();
/// assert_eq!(
///     window_bisect(rs, |x| x <= 5),
///     vec![2, 3, 4, 4, 6, 7, 7, 8, 8]
/// );
///
/// let rs: RangeSum = vec![6, 2, 5, 2, 3, 2, 1, 1, 1].into();
/// assert_eq!(
///     window_bisect(rs, |x| x <= 4),
///     vec![0, 2, 2, 4, 5, 8, 9, 9, 9]
/// );
/// ```
pub fn window_bisect<S, P>(mut slice: S, pred: P) -> Vec<usize>
where
    S: ElasticSlice + ExpandBack + ShrinkFront + SliceHash<Salt = ()>,
    S::Hashed: Clone,
    P: Fn(S::Hashed) -> bool,
{
    slice.reset();
    let n = slice.full_len();
    let mut res = vec![n; n];
    for l in 0..n {
        loop {
            let o = slice.hash(());
            if !pred(o) {
                res[l] = slice.end() - 1;
                break;
            }
            if slice.end() == n {
                return res;
            }
            slice.expand_back();
        }
        slice.shrink_front();
    }
    res
}