Skip to content

Commit 13ba220

Browse files
authored
linear rmq (#100)
* linear rmq * add docs * better golf --------- Co-authored-by: Luke Videckis <[email protected]>
1 parent 6d25c46 commit 13ba220

File tree

4 files changed

+129
-0
lines changed

4 files changed

+129
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,7 @@ path = "examples/data_structures/disjoint_rmq_non_commutative.rs"
235235
[[example]]
236236
name = "lca_rmq_next_on_path"
237237
path = "examples/graphs/lca_rmq_next_on_path.rs"
238+
239+
[[example]]
240+
name = "linear_rmq"
241+
path = "examples/data_structures/linear_rmq.rs"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/staticrmq
2+
3+
use proconio::input;
4+
use programming_team_code_rust::data_structures::linear_rmq::LinearRMQ;
5+
6+
fn main() {
7+
input! {
8+
n: usize,
9+
q: usize,
10+
a: [usize; n],
11+
}
12+
13+
let rmq = LinearRMQ::new(&a, |&x, &y| x.lt(&y));
14+
for _ in 0..q {
15+
input! {
16+
le: usize,
17+
ri: usize,
18+
}
19+
let idx_min = rmq.query_idx(le..ri);
20+
assert!((le..ri).contains(&idx_min));
21+
let res = rmq.query(le..ri);
22+
assert_eq!(a[idx_min], *res);
23+
println!("{}", res);
24+
}
25+
}

src/data_structures/linear_rmq.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+
}

src/data_structures/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod binary_trie;
33
pub mod disjoint_rmq;
44
pub mod fenwick;
55
pub mod lazy_seg_tree;
6+
pub mod linear_rmq;
67
pub mod range_container;
78
pub mod rmq;
89
pub mod seg_tree;

0 commit comments

Comments
 (0)