contest_algorithms/range_query/
dynamic_arq.rs

1//! Associative Range Query Tree with dynamic allocation, supporting sparse
2//! initialization and persistence
3use super::ArqSpec;
4
5pub struct DynamicArqNode<T: ArqSpec> {
6    val: T::S,
7    app: Option<T::F>,
8    down: (usize, usize),
9}
10
11// TODO: in a future Rust version, this might be replaced by a #[derive(Clone)]
12impl<T: ArqSpec> Clone for DynamicArqNode<T> {
13    fn clone(&self) -> Self {
14        Self {
15            val: self.val.clone(),
16            app: self.app.clone(),
17            down: self.down,
18        }
19    }
20}
21
22impl<T: ArqSpec> Default for DynamicArqNode<T> {
23    fn default() -> Self {
24        Self {
25            val: T::identity(),
26            app: None,
27            down: (usize::max_value(), usize::max_value()),
28        }
29    }
30}
31
32impl<T: ArqSpec> DynamicArqNode<T> {
33    fn apply(&mut self, f: &T::F, size: i64) {
34        self.val = T::apply(f, &self.val, size);
35        if size > 1 {
36            let h = match self.app {
37                Some(ref g) => T::compose(f, g),
38                None => f.clone(),
39            };
40            self.app = Some(h);
41        }
42    }
43}
44
45pub type ArqView = (usize, i64);
46
47/// A dynamic, and optionally persistent, associative range query data structure.
48pub struct DynamicArq<T: ArqSpec> {
49    nodes: Vec<DynamicArqNode<T>>,
50    is_persistent: bool,
51}
52
53impl<T: ArqSpec> DynamicArq<T> {
54    /// Initializes the data structure without creating any nodes.
55    pub fn new(is_persistent: bool) -> Self {
56        Self {
57            nodes: vec![],
58            is_persistent,
59        }
60    }
61
62    /// Lazily builds a tree initialized to the identity.
63    pub fn build_from_identity(&mut self, size: i64) -> ArqView {
64        self.nodes.push(DynamicArqNode::default());
65        (self.nodes.len() - 1, size)
66    }
67
68    /// Builds a tree whose leaves are set to a given non-empty slice.
69    pub fn build_from_slice(&mut self, init_val: &[T::S]) -> ArqView {
70        if init_val.len() == 1 {
71            let root = DynamicArqNode {
72                val: init_val[0].clone(),
73                ..Default::default()
74            };
75            self.nodes.push(root);
76            (self.nodes.len() - 1, 1)
77        } else {
78            let ls = init_val.len() / 2;
79            let (l_init, r_init) = init_val.split_at(ls);
80            let l_view = self.build_from_slice(l_init);
81            let r_view = self.build_from_slice(r_init);
82            self.merge_equal_sized(l_view, r_view)
83        }
84    }
85
86    /// Merges two balanced subtrees into a single tree with a 0-indexed view.
87    pub fn merge_equal_sized(&mut self, (lp, ls): ArqView, (rp, rs): ArqView) -> ArqView {
88        assert!(ls == rs || ls + 1 == rs);
89        let p = self.nodes.len();
90        let root = DynamicArqNode {
91            down: (lp, rp),
92            ..Default::default()
93        };
94        self.nodes.push(root);
95        self.pull(p);
96        (p, ls + rs)
97    }
98
99    pub fn push(&mut self, (p, s): ArqView) -> (ArqView, ArqView) {
100        if self.nodes[p].down.0 == usize::max_value() {
101            self.nodes.push(DynamicArqNode::default());
102            self.nodes.push(DynamicArqNode::default());
103            self.nodes[p].down = (self.nodes.len() - 2, self.nodes.len() - 1)
104        };
105        let (lp, rp) = self.nodes[p].down;
106        let ls = s / 2;
107        if let Some(ref f) = self.nodes[p].app.take() {
108            self.nodes[lp].apply(f, ls);
109            self.nodes[rp].apply(f, s - ls);
110        }
111        ((lp, ls), (rp, s - ls))
112    }
113
114    pub fn pull(&mut self, p: usize) {
115        let (lp, rp) = self.nodes[p].down;
116        let left_val = &self.nodes[lp].val;
117        let right_val = &self.nodes[rp].val;
118        self.nodes[p].val = T::op(left_val, right_val);
119    }
120
121    fn clone_node(&mut self, p_orig: usize) -> usize {
122        if self.is_persistent {
123            let node = self.nodes[p_orig].clone();
124            self.nodes.push(node);
125            self.nodes.len() - 1
126        } else {
127            p_orig
128        }
129    }
130
131    /// Applies the endomorphism f to all entries from l to r, inclusive.
132    /// If l == r, the updates are eager. Otherwise, they are lazy.
133    pub fn update(&mut self, view: ArqView, l: i64, r: i64, f: &T::F) -> ArqView {
134        let (p_orig, s) = view;
135        if r < 0 || s - 1 < l {
136            view
137        } else if l <= 0 && s - 1 <= r {
138            let p_clone = self.clone_node(p_orig);
139            self.nodes[p_clone].apply(f, s);
140            (p_clone, s)
141        } else {
142            let (l_view, r_view) = self.push(view);
143            let ls = l_view.1;
144            let p_clone = self.clone_node(p_orig);
145            let lp_clone = self.update(l_view, l, r, f).0;
146            let rp_clone = self.update(r_view, l - ls, r - ls, f).0;
147            self.nodes[p_clone].down = (lp_clone, rp_clone);
148            self.pull(p_clone);
149            (p_clone, s)
150        }
151    }
152
153    /// Returns the aggregate range query on all entries from l to r, inclusive.
154    pub fn query(&mut self, view: ArqView, l: i64, r: i64) -> T::S {
155        let (p, s) = view;
156        if r < 0 || s - 1 < l {
157            T::identity()
158        } else if l <= 0 && s - 1 <= r {
159            self.nodes[p].val.clone()
160        } else {
161            let (l_view, r_view) = self.push(view);
162            let ls = l_view.1;
163            let l_agg = self.query(l_view, l, r);
164            let r_agg = self.query(r_view, l - ls, r - ls);
165            T::op(&l_agg, &r_agg)
166        }
167    }
168}
169
170/// An example of binary search to find the first position whose element is negative.
171/// The DynamicArq version works on trees of any size, not necessarily a power of two.
172pub fn first_negative(arq: &mut DynamicArq<super::specs::AssignMin>, view: ArqView) -> Option<i64> {
173    let (p, s) = view;
174    if s == 1 {
175        Some(0).filter(|_| arq.nodes[p].val < 0)
176    } else {
177        let (l_view, r_view) = arq.push(view);
178        let (lp, ls) = l_view;
179        if arq.nodes[lp].val < 0 {
180            first_negative(arq, l_view)
181        } else {
182            first_negative(arq, r_view).map(|x| ls + x)
183        }
184    }
185}