|
| 1 | +//! # Linear Range Minimum Query |
| 2 | +
|
| 3 | +/// # Example |
| 4 | +/// ``` |
| 5 | +/// use programming_team_code_rust::data_structures::linear_rmq::LinearRMQ; |
| 6 | +/// |
| 7 | +/// let a = [1, 0, 2, 0, 3]; |
| 8 | +/// let rmq = LinearRMQ::new(&a, |&x, &y| x.lt(&y)); // lt -> right-most min |
| 9 | +/// // le -> left-most min |
| 10 | +/// // gt -> right-most max |
| 11 | +/// // ge -> left-most max |
| 12 | +/// assert_eq!(rmq.query_idx(0..5), 3); |
| 13 | +/// assert_eq!(*rmq.query(1..5), 0); |
| 14 | +/// ``` |
| 15 | +pub struct LinearRMQ<T, F> { |
| 16 | + a: Vec<T>, |
| 17 | + cmp: F, |
| 18 | + head: Vec<usize>, |
| 19 | + t: Vec<(usize, usize)>, |
| 20 | +} |
| 21 | + |
| 22 | +impl<T: Clone, F: Fn(&T, &T) -> bool> LinearRMQ<T, F> { |
| 23 | + /// Create a new LinearRMQ instance |
| 24 | + /// |
| 25 | + /// # Complexity (n = a.len()) |
| 26 | + /// - Time: O(n) |
| 27 | + /// - Space: O(n) |
| 28 | + pub fn new(a: &[T], cmp: F) -> Self { |
| 29 | + let mut head = vec![0; a.len() + 1]; |
| 30 | + let mut t = vec![(0, 0); a.len()]; |
| 31 | + let mut st = vec![usize::MAX]; |
| 32 | + for i in 0..=a.len() { |
| 33 | + let mut prev = usize::MAX; |
| 34 | + while *st.last().unwrap() != usize::MAX |
| 35 | + && (i == a.len() || !cmp(&a[*st.last().unwrap()], &a[i])) |
| 36 | + { |
| 37 | + if prev != usize::MAX { |
| 38 | + head[prev] = *st.last().unwrap(); |
| 39 | + } |
| 40 | + let pw2 = 1 << (st[st.len() - 2].wrapping_add(1) ^ i).ilog2(); |
| 41 | + prev = i & 0_usize.wrapping_sub(pw2); |
| 42 | + t[*st.last().unwrap()].0 = prev; |
| 43 | + st.pop(); |
| 44 | + t[(*st.last().unwrap()).wrapping_add(1)].1 |= pw2; |
| 45 | + } |
| 46 | + if prev != usize::MAX { |
| 47 | + head[prev] = i; |
| 48 | + } |
| 49 | + st.push(i); |
| 50 | + } |
| 51 | + for i in 1..a.len() { |
| 52 | + t[i].1 = |
| 53 | + (t[i].1 | t[i - 1].1) & 0_usize.wrapping_sub(t[i].0 & 0_usize.wrapping_sub(t[i].0)); |
| 54 | + } |
| 55 | + Self { |
| 56 | + a: a.to_vec(), |
| 57 | + cmp, |
| 58 | + head, |
| 59 | + t, |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + /// Gets the index of min/max of range |
| 64 | + /// |
| 65 | + /// # Complexity |
| 66 | + /// - Time: O(1) |
| 67 | + /// - Space: O(1) |
| 68 | + pub fn query_idx(&self, range: std::ops::Range<usize>) -> usize { |
| 69 | + assert!(!range.is_empty()); |
| 70 | + let (mut le, mut ri) = (range.start, range.end - 1); |
| 71 | + let j = self.t[le].1 |
| 72 | + & self.t[ri].1 |
| 73 | + & 0_usize.wrapping_sub(1 << ((self.t[le].0 ^ self.t[ri].0) | 1).ilog2()); |
| 74 | + let lift = |u: usize, mut k: usize| -> usize { |
| 75 | + if k == 0 { |
| 76 | + u |
| 77 | + } else { |
| 78 | + k = 1 << k.ilog2(); |
| 79 | + self.head[self.t[u].0 & 0_usize.wrapping_sub(k) | k] |
| 80 | + } |
| 81 | + }; |
| 82 | + le = lift(le, self.t[le].1 ^ j); |
| 83 | + ri = lift(ri, self.t[ri].1 ^ j); |
| 84 | + if (self.cmp)(&self.a[le], &self.a[ri]) { |
| 85 | + le |
| 86 | + } else { |
| 87 | + ri |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + /// Gets the min/max of range |
| 92 | + /// |
| 93 | + /// # Complexity |
| 94 | + /// - Time: O(1) |
| 95 | + /// - Space: O(1) |
| 96 | + pub fn query(&self, range: std::ops::Range<usize>) -> &T { |
| 97 | + &self.a[self.query_idx(range)] |
| 98 | + } |
| 99 | +} |
0 commit comments