|
| 1 | +//! # Disjoint Range Minimum Query |
| 2 | +
|
| 3 | +/// # Example |
| 4 | +/// ``` |
| 5 | +/// use programming_team_code_rust::data_structures::disjoint_rmq::DisjointRMQ; |
| 6 | +/// |
| 7 | +/// let a = [1, 3, 1, 4, 5]; |
| 8 | +/// // (min, number of mins) |
| 9 | +/// let rmq = DisjointRMQ::new(&a.iter().map(|&x| (x, 1)).collect::<Vec<_>>(), |&x, &y| { |
| 10 | +/// if x.0 == y.0 { |
| 11 | +/// (x.0, x.1 + y.1) |
| 12 | +/// } else { |
| 13 | +/// std::cmp::min(x, y) |
| 14 | +/// } |
| 15 | +/// }); |
| 16 | +/// assert_eq!(rmq.query(0..5), (1, 2)); |
| 17 | +/// assert_eq!(rmq.query(3..5), (4, 1)); |
| 18 | +/// assert!(std::panic::catch_unwind(|| rmq.query(1..1)).is_err()); |
| 19 | +/// ``` |
| 20 | +pub struct DisjointRMQ<T, F> { |
| 21 | + t: Vec<Vec<T>>, |
| 22 | + op: F, |
| 23 | +} |
| 24 | + |
| 25 | +impl<T: Clone, F: Fn(&T, &T) -> T> DisjointRMQ<T, F> { |
| 26 | + /// Create a new Disjoint RMQ instance |
| 27 | + /// |
| 28 | + /// # Complexity (n = a.len()) |
| 29 | + /// - Time: O(n log n) |
| 30 | + /// - Space: O(n log n) |
| 31 | + pub fn new(a: &[T], op: F) -> Self { |
| 32 | + let mut t = vec![]; |
| 33 | + let mut len = 1; |
| 34 | + while len <= a.len() { |
| 35 | + let mut le = 0; |
| 36 | + let mut row = a.to_vec(); |
| 37 | + while le < a.len() { |
| 38 | + let mi = (le + len).min(a.len()); |
| 39 | + let ri = (le + 2 * len).min(a.len()); |
| 40 | + for i in (le..mi - 1).rev() { |
| 41 | + row[i] = op(&row[i], &row[i + 1]); |
| 42 | + } |
| 43 | + for i in mi + 1..ri { |
| 44 | + row[i] = op(&row[i - 1], &row[i]); |
| 45 | + } |
| 46 | + le += 2 * len; |
| 47 | + } |
| 48 | + t.push(row); |
| 49 | + len *= 2; |
| 50 | + } |
| 51 | + Self { t, op } |
| 52 | + } |
| 53 | + |
| 54 | + /// Query the range [range.start, range.end) |
| 55 | + /// |
| 56 | + /// # Complexity |
| 57 | + /// - Time: O(1) |
| 58 | + /// - Space: O(1) |
| 59 | + pub fn query(&self, range: std::ops::Range<usize>) -> T { |
| 60 | + assert!(!range.is_empty()); |
| 61 | + if range.len() == 1 { |
| 62 | + self.t[0][range.start].clone() |
| 63 | + } else { |
| 64 | + let lg = (range.start ^ (range.end - 1)).ilog2() as usize; |
| 65 | + (self.op)(&self.t[lg][range.start], &self.t[lg][range.end - 1]) |
| 66 | + } |
| 67 | + } |
| 68 | +} |
0 commit comments