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}