contest_algorithms/range_query/
static_arq.rs

1//! Associative Range Query Tree
2use super::ArqSpec;
3
4/// Colloquially known as a "segtree" in the sport programming literature, it
5/// represents a sequence of elements a_i (0 <= i < size) from a monoid (S, +)
6/// on which we want to support fast range operations:
7///
8/// - update(l, r, f) replaces a_i (l <= i <= r) by f(a_i) for an endomorphism f
9/// - query(l, r) returns the aggregate a_l + a_{l+1} + ... + a_r
10///
11/// This compact representation is based on a [blog post by Al.Cash]
12/// (http://codeforces.com/blog/entry/18051). All nodes have 0 or 2 children.
13/// Hence, trees whose size is not a power of two will have multiple roots.
14///
15/// Future work: ArqTree would lend itself naturally to Rust's ownership system.
16/// Initially, we should only have access to the root nodes:
17///            if size is a power of two, there is a unique root at index 1.
18/// arq.push(i) locks i and acquires access to its children.
19/// arq.pull(i) is called when the lock on i is released.
20pub struct StaticArq<T: ArqSpec> {
21    val: Vec<T::S>,
22    app: Vec<Option<T::F>>,
23}
24
25impl<T: ArqSpec> StaticArq<T> {
26    /// Initializes a static balanced binary tree on top of the given sequence.
27    pub fn new(init_val: &[T::S]) -> Self {
28        let size = init_val.len();
29        let mut val = vec![T::identity(); size];
30        val.extend_from_slice(init_val);
31        let app = vec![None; size];
32
33        let mut arq = Self { val, app };
34        for p in (0..size).rev() {
35            arq.pull(p);
36        }
37        arq
38    }
39
40    fn apply(&mut self, p: usize, f: &T::F, s: i64) {
41        self.val[p] = T::apply(f, &self.val[p], s);
42        if let Some(lazy) = self.app.get_mut(p) {
43            let h = match *lazy {
44                Some(ref g) => T::compose(f, g),
45                None => f.clone(),
46            };
47            *lazy = Some(h);
48        }
49    }
50
51    fn push(&mut self, p: usize) {
52        if let Some(ref f) = self.app[p].take() {
53            let s = ((self.app.len() + p - 1) / p / 2).next_power_of_two() as i64;
54            self.apply(p << 1, f, s);
55            self.apply(p << 1 | 1, f, s);
56        }
57    }
58
59    fn pull(&mut self, p: usize) {
60        self.val[p] = T::op(&self.val[p << 1], &self.val[p << 1 | 1]);
61    }
62
63    fn push_to(&mut self, p: usize) {
64        let one_plus_floor_log_p = (p + 1).next_power_of_two().trailing_zeros();
65        for i in (1..one_plus_floor_log_p).rev() {
66            self.push(p >> i);
67        }
68    }
69
70    fn pull_from(&mut self, mut p: usize) {
71        while p > 1 {
72            p >>= 1;
73            self.pull(p);
74        }
75    }
76
77    /// Applies the endomorphism f to all entries from l to r, inclusive.
78    /// If l == r, the updates are eager. Otherwise, they are lazy.
79    ///
80    /// # Panics
81    ///
82    /// Panics if r >= size. Note that l > r is valid, meaning an empty range.
83    pub fn update(&mut self, mut l: usize, mut r: usize, f: &T::F) {
84        l += self.app.len();
85        r += self.app.len();
86        if l < r {
87            self.push_to(l);
88        }
89        self.push_to(r);
90        let (mut l0, mut r0, mut s) = (1, 1, 1);
91        while l <= r {
92            if l & 1 == 1 {
93                self.apply(l, f, s);
94                l0 = l0.max(l);
95                l += 1;
96            }
97            if r & 1 == 0 {
98                self.apply(r, f, s);
99                r0 = r0.max(r);
100                r -= 1;
101            }
102            l >>= 1;
103            r >>= 1;
104            s <<= 1;
105        }
106        self.pull_from(l0);
107        self.pull_from(r0);
108    }
109
110    /// Returns the aggregate range query on all entries from l to r, inclusive.
111    ///
112    /// # Panics
113    ///
114    /// Panics if r >= size. Note that l > r is valid, meaning an empty range.
115    pub fn query(&mut self, mut l: usize, mut r: usize) -> T::S {
116        l += self.app.len();
117        r += self.app.len();
118        if l < r {
119            self.push_to(l);
120        }
121        self.push_to(r);
122        let (mut l_agg, mut r_agg) = (T::identity(), T::identity());
123        while l <= r {
124            if l & 1 == 1 {
125                l_agg = T::op(&l_agg, &self.val[l]);
126                l += 1;
127            }
128            if r & 1 == 0 {
129                r_agg = T::op(&self.val[r], &r_agg);
130                r -= 1;
131            }
132            l >>= 1;
133            r >>= 1;
134        }
135        T::op(&l_agg, &r_agg)
136    }
137}
138
139/// An example of binary search to find the first position whose element is negative.
140/// In this case, we use RMQ to locate the leftmost negative element.
141/// To ensure the existence of a valid root note (i == 1) from which to descend,
142/// the tree's size must be a power of two.
143pub fn first_negative(arq: &mut StaticArq<super::specs::AssignMin>) -> Option<usize> {
144    assert!(arq.app.len().is_power_of_two());
145    let mut p = 1;
146    if arq.val[p] >= 0 {
147        None
148    } else {
149        while p < arq.app.len() {
150            arq.push(p);
151            p <<= 1;
152            if arq.val[p] >= 0 {
153                p |= 1;
154            }
155        }
156        Some(p - arq.app.len())
157    }
158}