array_range_query/
lazy_seg_tree.rs

1/*!
2Lazy Segment Tree (range-update, range-query) — generic implementation.
3
4## Overview
5
6This module implements a generic lazy segment tree: a binary tree stored in
7an array that supports efficient range updates and range queries.
8
9The implementation is deliberately generic and configurable via the
10`LazySegTreeSpec` trait. The trait allows you to define:
11- the stored value type `T` and the lazy-update type `U`,
12- how two values `T` are combined (aggregation),
13- how two updates `U` are composed, and
14- how a lazy update affects a node's stored aggregate (taking into account
15  the number of leaves covered by that node).
16
17## Design notes
18
19- API distinction between read and write:
20  - `query(&self, ...)` is provided as `&self`. Internally it uses
21    `RefCell` to push lazy tags while preserving a read-only public API.
22  - `update(&mut self, ...)` requires `&mut self` and uses direct mutable
23    access to the internal buffers for better performance and simpler
24    borrowing semantics.
25
26- Storage layout:
27  - A complete binary tree is stored in a `Vec` using 1-based indexing
28    (i.e. root at index `1`). The number of leaves is `max_size`, the next
29    power of two >= logical `size`. Total storage uses `max_size * 2` slots.
30
31- Ranges are half-open: `[left, right)`. This is consistent across
32  `query` and `update`.
33
34## Usage summary
35
361. Implement `LazySegTreeSpec` for your problem domain (range add / range
37   sum, range assign / range min, etc.).
382. Construct a tree:
39   - `LazySegTree::new(size)` creates a tree with all values set to `Spec::ID`.
40   - `LazySegTree::from_vec(values)` builds the tree from an initial slice.
413. Use `query` and `update` to perform operations. `query` will return the
42   aggregate over a half-open interval, and `update` will apply a lazy
43   update to every element in the interval.
44
45## Example (Range Add + Range Sum)
46
47
48```rust
49# use array_range_query::{LazySegTree, LazySegTreeSpec};
50# struct RangeAddSum;
51# impl LazySegTreeSpec for RangeAddSum {
52#     type T = i64;
53#     type U = i64;
54#     const ID: Self::T = 0;
55#     fn op_on_data(d1: &Self::T, d2: &Self::T) -> Self::T { d1 + d2 }
56#     fn op_on_update(u1: &Self::U, u2: &Self::U) -> Self::U { u1 + u2 }
57#     fn op_update_on_data(u: &Self::U, d: &Self::T, size: usize) -> Self::T {
58#         d + (u * size as i64)
59#     }
60# }
61let mut tree = LazySegTree::<RangeAddSum>::from_vec(&vec![1,2,3,4,5]);
62assert_eq!(tree.query(1, 4), 9); // 2 + 3 + 4
63tree.update(1, 4, 10); // add 10 to indices 1..4
64assert_eq!(tree.query(0, 5), 45);
65```
66
67## Panics and safety
68
69- `validate_range` asserts that `left <= right` and `right <= size`. If the
70  caller violates these preconditions the library panics with a helpful
71  message.
72- Because `query(&self, ..)` uses interior mutability (`RefCell`), a
73  runtime panic will occur if external code causes conflicting borrows that
74  violate `RefCell` rules. Typical use does not trigger this, but it is a
75  potential runtime failure mode to be aware of.
76*/
77
78use std::cell::RefCell;
79use std::fmt::Display;
80use std::marker::PhantomData;
81
82/// Specification trait for `LazySegTree`.
83///
84/// Implement this trait to define the concrete behavior of the tree:
85/// - `T`: data stored in nodes (the aggregate type),
86/// - `U`: lazy-update type (the tag type),
87/// - `ID`: identity element for `T`.
88///
89/// Required operations:
90/// - `op_on_data`          — combine two `T`s into one (e.g., sum or min),
91/// - `op_on_update`        — compose two updates `U` into a single update,
92/// - `op_update_on_data`   — apply an update `U` to `T` representing `size` leaves.
93pub trait LazySegTreeSpec {
94    type T: Clone;
95    type U: Clone;
96
97    /// Identity element for `T`.
98    const ID: Self::T;
99
100    /// Combine two child values into a parent value.
101    fn op_on_data(d1: &Self::T, d2: &Self::T) -> Self::T;
102
103    /// Compose two updates. If update `a` is applied before `b`, then the
104    /// composed update should be `op_on_update(a, b)` (document the intended
105    /// order in non-commutative cases).
106    fn op_on_update(u1: &Self::U, u2: &Self::U) -> Self::U;
107
108    /// Apply an update `u` to a node's stored aggregate `d` which represents
109    /// `size` leaves. For example, for range-add + range-sum:
110    /// `op_update_on_data(u, d, size) = d + u * size`.
111    fn op_update_on_data(u: &Self::U, d: &Self::T, size: usize) -> Self::T;
112
113    /// Helper to combine an existing optional tag with a new tag.
114    ///
115    /// Default behavior: if there is an existing tag, compose them using
116    /// `op_on_update`; otherwise, install `new_tag`.
117    fn op_on_update_option(existing_tag: &Option<Self::U>, new_tag: &Self::U) -> Option<Self::U> {
118        if let Some(existing) = existing_tag {
119            Some(Self::op_on_update(existing, new_tag))
120        } else {
121            Some(new_tag.clone())
122        }
123    }
124}
125
126/// Generic lazy segment tree.
127///
128/// The tree stores aggregates of type `Spec::T` and lazy tags of `Spec::U`.
129/// Public operations:
130/// - `new(size)` and `from_vec(values)` to construct,
131/// - `query(&self, left, right)` to query `[left, right)`,
132/// - `update(&mut self, left, right, value)` to apply a lazy update to `[left, right)`.
133#[derive(Clone, Debug)]
134pub struct LazySegTree<Spec: LazySegTreeSpec> {
135    size: usize,
136    max_size: usize,
137    data: RefCell<Vec<Spec::T>>,
138    tags: RefCell<Vec<Option<Spec::U>>>,
139    _spec: PhantomData<Spec>,
140}
141
142impl<Spec: LazySegTreeSpec> LazySegTree<Spec> {
143    /// Create a new tree of `size` elements, all initialized to `Spec::ID`.
144    ///
145    /// `max_size` (the number of leaves used internally) will be the next power
146    /// of two greater than or equal to `size`.
147    pub fn new(size: usize) -> Self {
148        let max_size = size.next_power_of_two();
149        Self {
150            size,
151            max_size,
152            data: RefCell::new(vec![Spec::ID; max_size * 2]),
153            tags: RefCell::new(vec![None; max_size * 2]),
154            _spec: PhantomData,
155        }
156    }
157
158    /// Build a tree from a slice of initial values. Complexity: O(n).
159    ///
160    /// The slice length determines the logical `size`.
161    pub fn from_vec(values: &[Spec::T]) -> Self {
162        let size = values.len();
163        let max_size = size.next_power_of_two();
164        let mut data = vec![Spec::ID; max_size * 2];
165
166        // Copy leaves and build internal nodes bottom-up.
167        if size > 0 {
168            data[max_size..(max_size + size)].clone_from_slice(values);
169            for i in (1..max_size).rev() {
170                data[i] = Spec::op_on_data(&data[i * 2], &data[i * 2 + 1]);
171            }
172        }
173
174        Self {
175            size,
176            max_size,
177            data: RefCell::new(data),
178            tags: RefCell::new(vec![None; max_size * 2]),
179            _spec: PhantomData,
180        }
181    }
182
183    /// Query the half-open interval `[left, right)`.
184    ///
185    /// Returns `Spec::ID` for empty ranges (`left == right`).
186    /// Panics if the range is invalid (see `validate_range`).
187    pub fn query(&self, left: usize, right: usize) -> Spec::T {
188        self.validate_range(left, right);
189        if left == right {
190            return Spec::ID;
191        }
192        self.query_internal(1, 0, left, right, self.max_size)
193    }
194
195    /// Apply `value` lazily to the half-open interval `[left, right)`.
196    ///
197    /// Requires `&mut self`. Panics if range is invalid.
198    pub fn update(&mut self, left: usize, right: usize, value: Spec::U) {
199        self.validate_range(left, right);
200        if left == right {
201            return;
202        }
203        self.update_internal(1, 0, left, right, self.max_size, value);
204    }
205
206    /// Push a pending tag at `index` down to the node's data and to its children.
207    ///
208    /// This version is used from `&self` paths (e.g. `query`) and therefore uses
209    /// `RefCell` borrows.
210    ///
211    /// `node_size` is the number of leaves covered by this node.
212    ///
213    /// # Panics
214    ///
215    /// Panics if `RefCell` borrow rules are violated (e.g., a conflicting borrow
216    /// exists when this method is called).
217    fn push(&self, index: usize, node_size: usize) {
218        // Borrow tags mutably. This may panic if a conflicting borrow exists.
219        let mut tags = self.tags.borrow_mut();
220        if let Some(tag) = tags[index].take() {
221            let mut data = self.data.borrow_mut();
222            let old_data = data[index].clone();
223            data[index] = Spec::op_update_on_data(&tag, &old_data, node_size);
224
225            if index < self.max_size {
226                tags[index * 2] = Spec::op_on_update_option(&tags[index * 2], &tag);
227                tags[index * 2 + 1] = Spec::op_on_update_option(&tags[index * 2 + 1], &tag);
228            }
229        }
230    }
231
232    /// Push a pending tag at `index` down using direct mutable access.
233    ///
234    /// Called from `&mut self` update paths; avoids `RefCell` overhead.
235    fn push_mut(&mut self, index: usize, node_size: usize) {
236        let tags = self.tags.get_mut();
237        if let Some(tag) = tags[index].take() {
238            let data = self.data.get_mut();
239            let old_data = data[index].clone();
240            data[index] = Spec::op_update_on_data(&tag, &old_data, node_size);
241
242            if index < self.max_size {
243                tags[index * 2] = Spec::op_on_update_option(&tags[index * 2], &tag);
244                tags[index * 2 + 1] = Spec::op_on_update_option(&tags[index * 2 + 1], &tag);
245            }
246        }
247    }
248
249    /// Recompute the value at `index` from its children.
250    ///
251    /// This uses direct mutable access via `get_mut()` because `pull_mut` is
252    /// only called from `&mut self` paths.
253    fn pull_mut(&mut self, index: usize) {
254        let data = self.data.get_mut();
255        data[index] = Spec::op_on_data(&data[index * 2], &data[index * 2 + 1]);
256    }
257
258    /// Internal recursive query implementation.
259    ///
260    /// - `index`: current node index in the array.
261    /// - `node_left..node_right`: interval covered by this node (half-open).
262    fn query_internal(
263        &self,
264        index: usize,
265        node_left: usize,
266        left: usize,
267        right: usize,
268        node_right: usize,
269    ) -> Spec::T {
270        // No overlap.
271        if node_right <= left || right <= node_left {
272            return Spec::ID;
273        }
274
275        // Ensure current node's pending tag (if any) is applied before reading.
276        self.push(index, node_right - node_left);
277        if left <= node_left && node_right <= right {
278            // Full cover.
279            return self.data.borrow()[index].clone();
280        } else {
281            // Partial cover — combine children.
282            let mid = (node_left + node_right) / 2;
283            let left_result = self.query_internal(index * 2, node_left, left, right, mid);
284            let right_result = self.query_internal(index * 2 + 1, mid, left, right, node_right);
285            Spec::op_on_data(&left_result, &right_result)
286        }
287    }
288
289    /// Internal recursive update implementation.
290    ///
291    /// Applies `value` to `[left, right)` within node covering `node_left..node_right`.
292    fn update_internal(
293        &mut self,
294        index: usize,
295        node_left: usize,
296        left: usize,
297        right: usize,
298        node_right: usize,
299        value: Spec::U,
300    ) {
301        // No overlap: ensure the node's pending tag (if any) is applied so that
302        // parent invariants remain correct.
303        if left >= node_right || right <= node_left {
304            self.push_mut(index, node_right - node_left);
305        } else if left <= node_left && node_right <= right {
306            // Fully covered: compose the new tag with any existing tag.
307            {
308                let tags = self.tags.get_mut();
309                tags[index] = Spec::op_on_update_option(&tags[index], &value);
310            }
311            // Apply it immediately to the node's stored data (and propagate to children).
312            self.push_mut(index, node_right - node_left);
313        } else {
314            // Partial overlap: push pending tag before recurring.
315            self.push_mut(index, node_right - node_left);
316            let mid = (node_left + node_right) / 2;
317            self.update_internal(index * 2, node_left, left, right, mid, value.clone());
318            self.update_internal(index * 2 + 1, mid, left, right, node_right, value);
319            // Recompute this node's aggregate after children updates.
320            self.pull_mut(index);
321        }
322    }
323
324    /// Validate the half-open range `[left, right)`.
325    ///
326    /// Panics with a descriptive message if the range is invalid.
327    fn validate_range(&self, left: usize, right: usize) {
328        assert!(
329            left <= right,
330            "Invalid range: `left` must be less than or equal to `right`. Got left: {}, right: {}",
331            left,
332            right
333        );
334        assert!(
335            right <= self.size,
336            "Out of bounds: `right` must be within the structure's size. Got right: {}, size: {}",
337            right,
338            self.size
339        );
340    }
341}
342
343/// Helper to pretty-print optional values arranged as a binary tree.
344///
345/// This helper is used by `Display` to render non-identity node values and
346/// pending tags for inspection/debugging.
347fn print_tree_option<T: Display>(
348    f: &mut std::fmt::Formatter<'_>,
349    tree: &Vec<&Option<T>>,
350    index: usize,
351    depth: usize,
352    l: usize,
353    r: usize,
354) -> std::fmt::Result {
355    if index >= tree.len() {
356        return Ok(());
357    }
358
359    if let Some(value) = &tree[index] {
360        for _ in 0..depth {
361            write!(f, "  ")?;
362        }
363        writeln!(f, "{} (Index: {}, Covers [{}, {}))", value, index, l, r)?;
364    }
365
366    if index * 2 + 1 < tree.len() {
367        print_tree_option(f, tree, index * 2, depth + 1, l, (l + r) / 2)?;
368        print_tree_option(f, tree, index * 2 + 1, depth + 1, (l + r) / 2, r)?;
369    }
370
371    Ok(())
372}
373
374impl<Spec: LazySegTreeSpec> Display for LazySegTree<Spec>
375where
376    Spec::T: Display + PartialEq,
377    Spec::U: Display,
378{
379    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
380        // Header: show types and logical size.
381        write!(f, "Type: {}", std::any::type_name::<Spec::T>())?;
382        write!(f, ", Update Type: {}", std::any::type_name::<Spec::U>())?;
383        write!(f, ", Size: {}", self.size)?;
384
385        // Inspect buffers.
386        let data = self.data.borrow();
387        let tags = self.tags.borrow();
388
389        // Convert `data` into Option<T> so we can show only non-identity entries.
390        let data_values: Vec<Option<Spec::T>> = data
391            .iter()
392            .map(|x| {
393                if *x != Spec::ID {
394                    Some(x.clone())
395                } else {
396                    None
397                }
398            })
399            .collect();
400        let data_values = data_values.iter().collect::<Vec<_>>();
401        let tag_values = tags.iter().collect::<Vec<_>>();
402
403        writeln!(f, "\nData: [")?;
404        print_tree_option(f, &data_values, 1, 1, 0, self.max_size)?;
405        writeln!(f, "]")?;
406
407        writeln!(f, "Tags: [")?;
408        print_tree_option(f, &tag_values, 1, 1, 0, self.max_size)?;
409        writeln!(f, "]")?;
410
411        Ok(())
412    }
413}
414
415#[cfg(test)]
416mod tests {
417    use super::*;
418
419    #[derive(Debug)]
420    struct RangeAddSum;
421    impl LazySegTreeSpec for RangeAddSum {
422        type T = i64;
423        type U = i64;
424        const ID: Self::T = 0;
425
426        fn op_on_data(d1: &Self::T, d2: &Self::T) -> Self::T {
427            d1 + d2
428        }
429        fn op_on_update(u1: &Self::U, u2: &Self::U) -> Self::U {
430            u1 + u2
431        }
432        fn op_update_on_data(u: &Self::U, d: &Self::T, size: usize) -> Self::T {
433            d + (u * size as i64)
434        }
435    }
436
437    #[test]
438    fn test_from_vec_and_initial_query() {
439        let tree = LazySegTree::<RangeAddSum>::from_vec(&[1, 2, 3, 4, 5]);
440        assert_eq!(tree.query(0, 5), 15);
441        assert_eq!(tree.query(2, 4), 7);
442    }
443
444    #[test]
445    fn test_update_and_query() {
446        let mut tree = LazySegTree::<RangeAddSum>::new(7);
447        tree.update(0, 5, 10); // Add 10 to first 5 elements
448        assert_eq!(tree.query(0, 7), 50);
449        tree.update(2, 7, -5); // Subtract 5 from elements 2,3,4,5,6
450        assert_eq!(tree.query(0, 2), 20); // 10 + 10
451        assert_eq!(tree.query(2, 5), 15); // (10-5) + (10-5) + (10-5)
452        assert_eq!(tree.query(0, 7), 25); // 20 + 15 + (-5 * 2)
453    }
454
455    #[test]
456    fn test_overlapping_updates() {
457        let mut tree = LazySegTree::<RangeAddSum>::new(10);
458        tree.update(0, 6, 5);
459        assert_eq!(tree.query(0, 10), 30);
460        tree.update(4, 8, 10);
461        let expected = (5 * 4) + ((5 + 10) * 2) + (10 * 2);
462        assert_eq!(tree.query(0, 10), expected);
463        assert_eq!(tree.query(4, 6), 30);
464    }
465
466    #[test]
467    #[should_panic]
468    fn test_panic_invalid_range() {
469        let tree = LazySegTree::<RangeAddSum>::new(10);
470        tree.query(5, 4);
471    }
472}