Skip to content

Commit b4ff259

Browse files
committed
linear rmq
1 parent 6d25c46 commit b4ff259

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-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: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//! # Linear Range Minimum Query
2+
3+
pub struct LinearRMQ<T, F> {
4+
a: Vec<T>,
5+
cmp: F,
6+
head: Vec<usize>,
7+
t: Vec<(usize, usize)>,
8+
}
9+
10+
impl<T: Clone, F: Fn(&T, &T) -> bool> LinearRMQ<T, F> {
11+
pub fn new(a: &[T], cmp: F) -> Self {
12+
let mut head = vec![0; a.len() + 1];
13+
let mut t = vec![(0, 0); a.len()];
14+
let mut st = vec![usize::MAX];
15+
for i in 0..=a.len() {
16+
let mut prev = usize::MAX;
17+
while *st.last().unwrap() != usize::MAX
18+
&& (i == a.len() || !cmp(&a[*st.last().unwrap()], &a[i]))
19+
{
20+
if prev != usize::MAX {
21+
head[prev] = *st.last().unwrap();
22+
}
23+
let pw2 = 1 << (st[st.len() - 2].wrapping_add(1) ^ i).ilog2();
24+
prev = i & 0_usize.wrapping_sub(pw2);
25+
t[*st.last().unwrap()].0 = prev;
26+
st.pop();
27+
t[(*st.last().unwrap()).wrapping_add(1)].1 |= pw2;
28+
}
29+
if prev != usize::MAX {
30+
head[prev] = i;
31+
}
32+
st.push(i);
33+
}
34+
for i in 1..a.len() {
35+
t[i].1 =
36+
(t[i].1 | t[i - 1].1) & 0_usize.wrapping_sub(t[i].0 & 0_usize.wrapping_sub(t[i].0));
37+
}
38+
Self {
39+
a: a.to_vec(),
40+
cmp,
41+
head,
42+
t,
43+
}
44+
}
45+
46+
pub fn query_idx(&self, range: std::ops::Range<usize>) -> usize {
47+
assert!(!range.is_empty());
48+
let (mut le, mut ri) = (range.start, range.end - 1);
49+
let j = self.t[le].1
50+
& self.t[ri].1
51+
& 0_usize.wrapping_sub(1 << ((self.t[le].0 ^ self.t[ri].0) | 1).ilog2());
52+
{
53+
let mut k = self.t[le].1 ^ j;
54+
if k != 0 {
55+
k = 1 << k.ilog2();
56+
le = self.head[self.t[le].0 & 0_usize.wrapping_sub(k) | k];
57+
}
58+
}
59+
{
60+
let mut k = self.t[ri].1 ^ j;
61+
if k != 0 {
62+
k = 1 << k.ilog2();
63+
ri = self.head[self.t[ri].0 & 0_usize.wrapping_sub(k) | k];
64+
}
65+
}
66+
if (self.cmp)(&self.a[le], &self.a[ri]) {
67+
le
68+
} else {
69+
ri
70+
}
71+
}
72+
73+
pub fn query(&self, range: std::ops::Range<usize>) -> &T {
74+
&self.a[self.query_idx(range)]
75+
}
76+
}

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)