Skip to content

Commit

Permalink
Merge branch 'main' into hld_nits
Browse files Browse the repository at this point in the history
  • Loading branch information
cameroncuster authored Jul 26, 2024
2 parents ee4dbb5 + 13ba220 commit f890e88
Show file tree
Hide file tree
Showing 10 changed files with 353 additions and 8 deletions.
18 changes: 15 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,16 @@ name = "lis_yosupo"
path = "examples/helpers/lis_yosupo.rs"

[[example]]
name = "lis_pop"
path = "examples/helpers/lis_pop.rs"
name = "lis_handmade"
path = "examples/helpers/lis_handmade.rs"

[[example]]
name = "range_container_aizu"
path = "examples/data_structures/range_container_aizu.rs"

[[example]]
name = "range_container_handmade"
path = "examples/data_structures/range_container_handmade.rs"

[[example]]
name = "mono_st"
Expand All @@ -222,4 +230,8 @@ 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"
path = "examples/graphs/lca_rmq_next_on_path.rs"

[[example]]
name = "linear_rmq"
path = "examples/data_structures/linear_rmq.rs"
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- tests are named `[algo].rs`
- use both yosupo and aizu to test whenever possible because bugs have existed on one of the sites but not the other
- when using both sites name the files `[algo]_yosupo.rs` and `[algo]_aizu.rs`
- when there's no problem to test on, test on [hello world](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/all/ITP1_1_A) and name the files `[algo]_handmade.rs`
- when only testing a specific function or componenet of some algorithm name the file `[algo]_[component].rs`

# Documentation Guidelines
Expand Down
25 changes: 25 additions & 0 deletions examples/data_structures/linear_rmq.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
45 changes: 45 additions & 0 deletions examples/data_structures/range_container_aizu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/DSL_2_D

use proconio::input;
use programming_team_code_rust::data_structures::range_container::RangeContainer;

fn main() {
input! {
n: usize,
q: usize,
}
let mut rc = RangeContainer::default();
let mut to_value = vec![i32::MAX; 2 * n + 2];
rc.insert_range(0..(2 * n + 1) as i32);

for _ in 0..q {
input! {
kind: usize,
}
match kind {
0 => {
input! {
le: i32,
ri: i32,
x: i32,
}
let le = 2 * le;
let ri = 2 * ri;
let save_range = rc.get_range(ri + 2).unwrap();
let save_value = to_value[save_range.start as usize];
rc.remove_range(le - 1..ri + 2);
rc.insert_range(le..ri + 1);
let save_range = rc.get_range(ri + 2).unwrap();
to_value[save_range.start as usize] = save_value;
to_value[le as usize] = x;
}
_ => {
input! {
index: i32,
}
let range_containing = rc.get_range(2 * index).unwrap();
println!("{}", to_value[range_containing.start as usize]);
}
}
}
}
64 changes: 64 additions & 0 deletions examples/data_structures/range_container_handmade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/all/ITP1_1_A

use programming_team_code_rust::data_structures::range_container::RangeContainer;
use rand::{thread_rng, Rng};
use std::collections::BTreeMap;

fn main() {
let mut rng = thread_rng();
for _ in 0..100 {
let max_n = rng.gen_range(1..100);
let mut vis = vec![false; max_n + 1];
let mut rc = RangeContainer::default();
for _ in 0..100 {
let mut le = rng.gen_range(0..=max_n);
let mut ri = rng.gen_range(0..=max_n);
if le > ri {
(le, ri) = (ri, le);
}
match rng.gen_range(0..2) {
0 => {
rc.insert_range(le as i32..ri as i32);
for elem in vis.iter_mut().take(ri).skip(le) {
*elem = true;
}
}
_ => {
rc.remove_range(le as i32..ri as i32);
for elem in vis.iter_mut().take(ri).skip(le) {
*elem = false;
}
}
}
let mut to_end = vec![None; max_n + 1];
for i in (0..max_n).rev() {
if vis[i] && !vis[i + 1] {
to_end[i] = Some(i + 1);
} else if vis[i] {
to_end[i] = to_end[i + 1];
}
}
let mut naive_mp = BTreeMap::<i32, i32>::new();
let mut start = None;
for i in 0..max_n + 1 {
if vis[i] {
if start.is_none() {
start = Some(i);
}
assert_eq!(
rc.get_range(i as i32).unwrap(),
start.unwrap() as i32..to_end[i].unwrap() as i32
);
} else {
assert_eq!(rc.get_range(i as i32), None);
if let Some(curr_start) = start {
naive_mp.insert(curr_start as i32, i as i32);
}
start = None;
}
}
assert_eq!(rc.mp, naive_mp);
}
}
println!("Hello World");
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/all/ITP1_1_A

use programming_team_code_rust::helpers::lis::Lis;
use rand::{thread_rng, Rng};

fn lis_quadratic(a: &[i32]) -> usize {
let n = a.len();
Expand All @@ -19,13 +20,14 @@ fn lis_quadratic(a: &[i32]) -> usize {
}

fn main() {
let mut rng = thread_rng();
for _ in 0..100 {
let mut lis = Lis::default();
let mut a = Vec::new();
for _ in 0..1000 {
match rand::random::<u8>() % 3 {
match rng.gen_range(0..3) {
0 => {
let new_num = rand::random::<i32>();
let new_num = rng.r#gen();
lis.push(new_num);
a.push(new_num);
}
Expand Down
99 changes: 99 additions & 0 deletions src/data_structures/linear_rmq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! # 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<T, F> {
a: Vec<T>,
cmp: F,
head: Vec<usize>,
t: Vec<(usize, usize)>,
}

impl<T: Clone, F: Fn(&T, &T) -> bool> LinearRMQ<T, F> {
/// 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()];
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,
}
}

/// 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>) -> 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 lift = |u: usize, mut k: usize| -> usize {
if k == 0 {
u
} else {
k = 1 << k.ilog2();
self.head[self.t[u].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 {
ri
}
}

/// Gets the min/max of range
///
/// # Complexity
/// - Time: O(1)
/// - Space: O(1)
pub fn query(&self, range: std::ops::Range<usize>) -> &T {
&self.a[self.query_idx(range)]
}
}
2 changes: 2 additions & 0 deletions src/data_structures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ 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;
pub mod trie;
Loading

0 comments on commit f890e88

Please sign in to comment.