From b4ff259d91aaf1161dd743792f2bcdcfcf12e055 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Mon, 22 Jul 2024 12:04:31 -0500 Subject: [PATCH 1/3] linear rmq --- Cargo.toml | 4 ++ examples/data_structures/linear_rmq.rs | 25 +++++++++ src/data_structures/linear_rmq.rs | 76 ++++++++++++++++++++++++++ src/data_structures/mod.rs | 1 + 4 files changed, 106 insertions(+) create mode 100644 examples/data_structures/linear_rmq.rs create mode 100644 src/data_structures/linear_rmq.rs diff --git a/Cargo.toml b/Cargo.toml index 3a8b26c..2785281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -235,3 +235,7 @@ path = "examples/data_structures/disjoint_rmq_non_commutative.rs" [[example]] name = "lca_rmq_next_on_path" path = "examples/graphs/lca_rmq_next_on_path.rs" + +[[example]] +name = "linear_rmq" +path = "examples/data_structures/linear_rmq.rs" diff --git a/examples/data_structures/linear_rmq.rs b/examples/data_structures/linear_rmq.rs new file mode 100644 index 0000000..31f3dc1 --- /dev/null +++ b/examples/data_structures/linear_rmq.rs @@ -0,0 +1,25 @@ +// verification-helper: PROBLEM https://judge.yosupo.jp/problem/staticrmq + +use proconio::input; +use programming_team_code_rust::data_structures::linear_rmq::LinearRMQ; + +fn main() { + input! { + n: usize, + q: usize, + a: [usize; n], + } + + let rmq = LinearRMQ::new(&a, |&x, &y| x.lt(&y)); + for _ in 0..q { + input! { + le: usize, + ri: usize, + } + let idx_min = rmq.query_idx(le..ri); + assert!((le..ri).contains(&idx_min)); + let res = rmq.query(le..ri); + assert_eq!(a[idx_min], *res); + println!("{}", res); + } +} diff --git a/src/data_structures/linear_rmq.rs b/src/data_structures/linear_rmq.rs new file mode 100644 index 0000000..d083deb --- /dev/null +++ b/src/data_structures/linear_rmq.rs @@ -0,0 +1,76 @@ +//! # Linear Range Minimum Query + +pub struct LinearRMQ { + a: Vec, + cmp: F, + head: Vec, + t: Vec<(usize, usize)>, +} + +impl bool> LinearRMQ { + pub fn new(a: &[T], cmp: F) -> Self { + let mut head = vec![0; a.len() + 1]; + let mut t = vec![(0, 0); a.len()]; + let mut st = vec![usize::MAX]; + for i in 0..=a.len() { + let mut prev = usize::MAX; + while *st.last().unwrap() != usize::MAX + && (i == a.len() || !cmp(&a[*st.last().unwrap()], &a[i])) + { + if prev != usize::MAX { + head[prev] = *st.last().unwrap(); + } + let pw2 = 1 << (st[st.len() - 2].wrapping_add(1) ^ i).ilog2(); + prev = i & 0_usize.wrapping_sub(pw2); + t[*st.last().unwrap()].0 = prev; + st.pop(); + t[(*st.last().unwrap()).wrapping_add(1)].1 |= pw2; + } + if prev != usize::MAX { + head[prev] = i; + } + st.push(i); + } + for i in 1..a.len() { + t[i].1 = + (t[i].1 | t[i - 1].1) & 0_usize.wrapping_sub(t[i].0 & 0_usize.wrapping_sub(t[i].0)); + } + Self { + a: a.to_vec(), + cmp, + head, + t, + } + } + + pub fn query_idx(&self, range: std::ops::Range) -> usize { + assert!(!range.is_empty()); + let (mut le, mut ri) = (range.start, range.end - 1); + let j = self.t[le].1 + & self.t[ri].1 + & 0_usize.wrapping_sub(1 << ((self.t[le].0 ^ self.t[ri].0) | 1).ilog2()); + { + let mut k = self.t[le].1 ^ j; + if k != 0 { + k = 1 << k.ilog2(); + le = self.head[self.t[le].0 & 0_usize.wrapping_sub(k) | k]; + } + } + { + let mut k = self.t[ri].1 ^ j; + if k != 0 { + k = 1 << k.ilog2(); + ri = self.head[self.t[ri].0 & 0_usize.wrapping_sub(k) | k]; + } + } + if (self.cmp)(&self.a[le], &self.a[ri]) { + le + } else { + ri + } + } + + pub fn query(&self, range: std::ops::Range) -> &T { + &self.a[self.query_idx(range)] + } +} diff --git a/src/data_structures/mod.rs b/src/data_structures/mod.rs index 3ea3e01..6e101f9 100644 --- a/src/data_structures/mod.rs +++ b/src/data_structures/mod.rs @@ -3,6 +3,7 @@ pub mod binary_trie; pub mod disjoint_rmq; pub mod fenwick; pub mod lazy_seg_tree; +pub mod linear_rmq; pub mod range_container; pub mod rmq; pub mod seg_tree; From 4f99febc60b0d2a0722ef79e740195cd26f0bdda Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Mon, 22 Jul 2024 12:12:10 -0500 Subject: [PATCH 2/3] add docs --- src/data_structures/linear_rmq.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/data_structures/linear_rmq.rs b/src/data_structures/linear_rmq.rs index d083deb..81d7d8b 100644 --- a/src/data_structures/linear_rmq.rs +++ b/src/data_structures/linear_rmq.rs @@ -1,5 +1,17 @@ //! # Linear Range Minimum Query +/// # Example +/// ``` +/// use programming_team_code_rust::data_structures::linear_rmq::LinearRMQ; +/// +/// let a = [1, 0, 2, 0, 3]; +/// let rmq = LinearRMQ::new(&a, |&x, &y| x.lt(&y)); // lt -> right-most min +/// // le -> left-most min +/// // gt -> right-most max +/// // ge -> left-most max +/// assert_eq!(rmq.query_idx(0..5), 3); +/// assert_eq!(*rmq.query(1..5), 0); +/// ``` pub struct LinearRMQ { a: Vec, cmp: F, @@ -8,6 +20,11 @@ pub struct LinearRMQ { } impl bool> LinearRMQ { + /// Create a new LinearRMQ instance + /// + /// # Complexity (n = a.len()) + /// - Time: O(n) + /// - Space: O(n) pub fn new(a: &[T], cmp: F) -> Self { let mut head = vec![0; a.len() + 1]; let mut t = vec![(0, 0); a.len()]; @@ -43,6 +60,11 @@ impl bool> LinearRMQ { } } + /// Gets the index of min/max of range + /// + /// # Complexity + /// - Time: O(1) + /// - Space: O(1) pub fn query_idx(&self, range: std::ops::Range) -> usize { assert!(!range.is_empty()); let (mut le, mut ri) = (range.start, range.end - 1); @@ -70,6 +92,11 @@ impl bool> LinearRMQ { } } + /// Gets the min/max of range + /// + /// # Complexity + /// - Time: O(1) + /// - Space: O(1) pub fn query(&self, range: std::ops::Range) -> &T { &self.a[self.query_idx(range)] } From effd6a5725e26c0acafb78447dc45accf44ed837 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Mon, 22 Jul 2024 12:20:45 -0500 Subject: [PATCH 3/3] better golf --- src/data_structures/linear_rmq.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/data_structures/linear_rmq.rs b/src/data_structures/linear_rmq.rs index 81d7d8b..8c8977e 100644 --- a/src/data_structures/linear_rmq.rs +++ b/src/data_structures/linear_rmq.rs @@ -71,20 +71,16 @@ impl bool> LinearRMQ { let j = self.t[le].1 & self.t[ri].1 & 0_usize.wrapping_sub(1 << ((self.t[le].0 ^ self.t[ri].0) | 1).ilog2()); - { - let mut k = self.t[le].1 ^ j; - if k != 0 { + let lift = |u: usize, mut k: usize| -> usize { + if k == 0 { + u + } else { k = 1 << k.ilog2(); - le = self.head[self.t[le].0 & 0_usize.wrapping_sub(k) | k]; + self.head[self.t[u].0 & 0_usize.wrapping_sub(k) | k] } - } - { - let mut k = self.t[ri].1 ^ j; - if k != 0 { - k = 1 << k.ilog2(); - ri = self.head[self.t[ri].0 & 0_usize.wrapping_sub(k) | k]; - } - } + }; + le = lift(le, self.t[le].1 ^ j); + ri = lift(ri, self.t[ri].1 ^ j); if (self.cmp)(&self.a[le], &self.a[ri]) { le } else {