use std::cmp::min_by;
use std::collections::Bound;
use std::mem::size_of;
use std::ops::{Deref, RangeBounds};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "mem_dbg", derive(mem_dbg::MemSize, mem_dbg::MemDbg))]
pub struct BinaryRmq {
data: Vec<u64>,
results: Vec<u32>,
}
impl BinaryRmq {
#[must_use]
pub fn from_vec(data: Vec<u64>) -> Self {
let len = data.len();
assert!(u32::try_from(len).is_ok(), "input too large for binary rmq");
let row_length = len.next_power_of_two().trailing_zeros() as usize + 1;
let mut results = vec![0u32; len * row_length];
for i in 0..len {
results[i * row_length] = 0;
}
for i in 0..data.len().next_power_of_two().trailing_zeros() {
let i = i as usize;
for j in 0..data.len() {
let offset = 1 << i;
#[allow(clippy::collapsible_else_if)] let arg_min: usize = if j + offset < data.len() {
if data[results[j * row_length + i] as usize + j]
< data[results[(j + offset) * row_length + i] as usize + (j + offset)]
{
results[j * row_length + i] as usize + j
} else {
results[(j + offset) * row_length + i] as usize + (j + offset)
}
} else {
if data.len() - offset - 1 > j {
if data[results[j * row_length + i] as usize + j]
< data[results[(data.len() - offset - 1) * row_length + i - 1] as usize
+ (data.len() - offset - 1)]
{
results[j * row_length + i] as usize + j
} else {
results[(data.len() - offset - 1) * row_length + i - 1] as usize
+ (data.len() - offset - 1)
}
} else {
j
}
};
#[allow(clippy::cast_possible_truncation)]
{
results[j * row_length + i + 1] = (arg_min - j) as u32;
}
}
}
Self { data, results }
}
#[must_use]
pub fn range_min_with_range<T: RangeBounds<usize>>(&self, range: T) -> usize {
let start = match range.start_bound() {
Bound::Included(i) => *i,
Bound::Excluded(i) => *i + 1,
Bound::Unbounded => 0,
}
.clamp(0, self.len() - 1);
let end = match range.end_bound() {
Bound::Included(i) => *i,
Bound::Excluded(i) => *i - 1,
Bound::Unbounded => self.len() - 1,
}
.clamp(0, self.len() - 1);
self.range_min(start, end)
}
#[must_use]
pub fn range_min(&self, i: usize, j: usize) -> usize {
let row_len = self.data.len().next_power_of_two().trailing_zeros() as usize + 1;
let log_dist = (usize::BITS - (j - i).leading_zeros()).saturating_sub(1) as usize;
let dist = (1 << log_dist) - 1;
min_by(
self.results[i * row_len + log_dist] as usize + i,
self.results[(j - dist) * row_len + log_dist] as usize + (j - dist),
|a, b| self.data[*a].cmp(&self.data[*b]),
)
}
#[must_use]
pub fn heap_size(&self) -> usize {
self.data.len() * size_of::<u64>() + self.results.len() * size_of::<u32>()
}
}
impl Deref for BinaryRmq {
type Target = Vec<u64>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl From<Vec<u64>> for BinaryRmq {
fn from(data: Vec<u64>) -> Self {
Self::from_vec(data)
}
}
impl FromIterator<u64> for BinaryRmq {
fn from_iter<T: IntoIterator<Item = u64>>(iter: T) -> Self {
Self::from_vec(iter.into_iter().collect())
}
}
#[cfg(test)]
mod tests;