diff --git a/Cargo.toml b/Cargo.toml index 604678ed..bfadebd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,12 +125,8 @@ name = "hld_path_composite_yosupo" path = "examples/graphs/hld_path_composite_yosupo.rs" [[example]] -name = "hld_jump_on_tree_nodes" -path = "examples/graphs/hld_jump_on_tree_nodes.rs" - -[[example]] -name = "hld_jump_on_tree_edges" -path = "examples/graphs/hld_jump_on_tree_edges.rs" +name = "hld_jump_on_path" +path = "examples/graphs/hld_jump_on_path.rs" [[example]] name = "hopcroft_karp_yosupo" @@ -201,13 +197,25 @@ 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" path = "examples/monotonic/mono_st.rs" +[[example]] +name = "hld_aux_tree" +path = "examples/graphs/hld_aux_tree.rs" + [[example]] name = "count_rects" path = "examples/monotonic/count_rects.rs" @@ -231,3 +239,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" \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index d218d77c..5c4e1ae0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -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 diff --git a/examples/data_structures/linear_rmq.rs b/examples/data_structures/linear_rmq.rs new file mode 100644 index 00000000..31f3dc1f --- /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/examples/data_structures/range_container_aizu.rs b/examples/data_structures/range_container_aizu.rs new file mode 100644 index 00000000..59fa2794 --- /dev/null +++ b/examples/data_structures/range_container_aizu.rs @@ -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]); + } + } + } +} diff --git a/examples/data_structures/range_container_handmade.rs b/examples/data_structures/range_container_handmade.rs new file mode 100644 index 00000000..e26762a7 --- /dev/null +++ b/examples/data_structures/range_container_handmade.rs @@ -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::::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"); +} diff --git a/examples/graphs/hld_aux_tree.rs b/examples/graphs/hld_aux_tree.rs new file mode 100644 index 00000000..deed9fa9 --- /dev/null +++ b/examples/graphs/hld_aux_tree.rs @@ -0,0 +1,80 @@ +// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_B + +use proconio::input; +use programming_team_code_rust::graphs::hld::HLD; +use std::collections::VecDeque; + +fn main() { + input! { + n: usize, + edges: [(usize, usize, u32); n - 1], + } + + let mut adj_weighted = vec![vec![]; n]; + let mut adj = vec![vec![]; n]; + for &(u, v, w) in &edges { + adj[u].push(v); + adj[v].push(u); + adj_weighted[u].push((v, w)); + adj_weighted[v].push((u, w)); + } + let adj_weighted = adj_weighted; + + let mut dist = vec![0; n]; + { + fn dfs(u: usize, p: Option, adj_weighted: &[Vec<(usize, u32)>], dist: &mut [u32]) { + for &(v, w) in &adj_weighted[u] { + if Some(v) == p { + continue; + } + dist[v] = w + dist[u]; + dfs(v, Some(u), adj_weighted, dist); + } + } + dfs(0, None, &adj_weighted, &mut dist); + } + let dist = dist; + + let hld = HLD::new(&mut adj, true); + + let weighted_dist = |u: usize, v: usize| -> u32 { + let lc = hld.lca(u, v); + dist[u] + dist[v] - 2 * dist[lc] + }; + + let mut diam_u = 0; + for i in 1..n { + if weighted_dist(0, i) > weighted_dist(0, diam_u) { + diam_u = i; + } + } + let mut diam_v = 0; + for i in 1..n { + if weighted_dist(diam_u, i) > weighted_dist(diam_u, diam_v) { + diam_v = i; + } + } + + for u in 0..n { + let (par, to_node) = hld.aux_tree(vec![diam_u, diam_v, u]); + let mut aux_adj = vec![vec![]; par.len()]; + for i in 1..par.len() { + let edge_w = dist[to_node[i]] - dist[to_node[par[i]]]; + aux_adj[i].push((par[i], edge_w)); + aux_adj[par[i]].push((i, edge_w)); + } + let mut q = VecDeque::new(); + q.push_back((to_node.iter().position(|&x| x == u).unwrap(), None, 0)); + let mut res = 0; + while let Some((node, parent, curr_dist)) = q.pop_front() { + res = res.max(curr_dist); + for &(v, w) in &aux_adj[node] { + if Some(v) == parent { + continue; + } + q.push_back((v, Some(node), curr_dist + w)); + } + } + println!("{}", res); + } +} diff --git a/examples/graphs/hld_jump_on_tree_edges.rs b/examples/graphs/hld_jump_on_path.rs similarity index 89% rename from examples/graphs/hld_jump_on_tree_edges.rs rename to examples/graphs/hld_jump_on_path.rs index 3d8e6fbf..97de62eb 100644 --- a/examples/graphs/hld_jump_on_tree_edges.rs +++ b/examples/graphs/hld_jump_on_path.rs @@ -28,6 +28,9 @@ fn main() { k: usize, } + assert_eq!(hld.kth_par(u, hld.d[u]), Some(0)); + assert_eq!(hld.kth_par(u, hld.d[u] + 1), None); + match hld.kth_on_path(u, v, k) { Some(w) => { assert!(k <= hld.dist(u, v)); diff --git a/examples/graphs/hld_jump_on_tree_nodes.rs b/examples/graphs/hld_jump_on_tree_nodes.rs deleted file mode 100644 index b1f770ed..00000000 --- a/examples/graphs/hld_jump_on_tree_nodes.rs +++ /dev/null @@ -1,59 +0,0 @@ -// verification-helper: PROBLEM https://judge.yosupo.jp/problem/jump_on_tree - -use proconio::input; -use programming_team_code_rust::graphs::hld::HLD; - -fn main() { - input! { - n: usize, - q: usize, - } - - let mut adj = vec![vec![]; n]; - for _ in 1..n { - input! { - u: usize, - v: usize - } - adj[u].push(v); - adj[v].push(u); - } - - let hld = HLD::new(&mut adj, false); - - fn dfs(u: usize, adj: &[Vec], d: &mut [usize]) { - for &v in &adj[u] { - d[v] = 1 + d[u]; - dfs(v, adj, d); - } - } - - let mut d = vec![0; n]; - dfs(0, &adj, &mut d); - - for _ in 0..q { - input! { - u: usize, - v: usize, - k: usize, - } - - let in_sub_naive = hld.kth_par(v, d[u].abs_diff(d[v])) == Some(u); - assert_eq!(in_sub_naive, hld.in_sub(u, v)); - - match hld.kth_on_path(u, v, k) { - Some(w) => { - assert!(k < hld.dist(u, v)); - assert!(hld.on_path(u, v, w)); - if w != u { - assert!(!hld.on_path(v, w, u)); - } - println!("{}", w); - } - None => { - assert!(k >= hld.dist(u, v)); - println!("-1"); - } - } - } -} diff --git a/examples/helpers/lis_pop.rs b/examples/helpers/lis_handmade.rs similarity index 89% rename from examples/helpers/lis_pop.rs rename to examples/helpers/lis_handmade.rs index e506c1eb..8815bd89 100644 --- a/examples/helpers/lis_pop.rs +++ b/examples/helpers/lis_handmade.rs @@ -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(); @@ -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::() % 3 { + match rng.gen_range(0..3) { 0 => { - let new_num = rand::random::(); + let new_num = rng.r#gen(); lis.push(new_num); a.push(new_num); } diff --git a/src/data_structures/linear_rmq.rs b/src/data_structures/linear_rmq.rs new file mode 100644 index 00000000..8c8977e1 --- /dev/null +++ b/src/data_structures/linear_rmq.rs @@ -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 { + a: Vec, + cmp: F, + head: Vec, + t: Vec<(usize, usize)>, +} + +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()]; + 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 { + 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) -> &T { + &self.a[self.query_idx(range)] + } +} diff --git a/src/data_structures/mod.rs b/src/data_structures/mod.rs index 05811f4b..6f0d9aea 100644 --- a/src/data_structures/mod.rs +++ b/src/data_structures/mod.rs @@ -4,6 +4,8 @@ pub mod deq_agg; 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; diff --git a/src/data_structures/range_container.rs b/src/data_structures/range_container.rs new file mode 100644 index 00000000..91c96a7e --- /dev/null +++ b/src/data_structures/range_container.rs @@ -0,0 +1,98 @@ +//! # Range Container + +use std::collections::BTreeMap; +use std::ops::Range; + +/// # Example +/// ``` +/// use programming_team_code_rust::data_structures::range_container::RangeContainer; +/// +/// let mut rc = RangeContainer::default(); +/// rc.insert_range(-2..2); +/// rc.insert_range(2..3); +/// assert_eq!(rc.get_range(0), Some(-2..3)); +/// assert_eq!(rc.get_range(3), None); +/// rc.remove_range(-1..1); +/// +/// assert_eq!(rc.get_range(-2), Some(-2..-1)); +/// assert_eq!(rc.get_range(2), Some(1..3)); +/// ``` +#[derive(Default)] +pub struct RangeContainer { + /// an entry le -> ri represents a range [le, ri) + /// invariant: previous_ri < current_le + pub mp: BTreeMap, +} + +impl RangeContainer { + fn remove(&mut self, range: &Range) -> Option { + let mut last_ri = None; + for (le, ri) in self + .mp + .range(range.start..=range.end) + .map(|(&le, &ri)| (le, ri)) + .collect::>() + { + self.mp.remove(&le); + last_ri = Some(ri); + } + last_ri + } + + /// Inserts a range into the container + /// + /// # Complexity + /// - Time: O(log n) ammortized + /// - Space: O(1) ammortized + pub fn insert_range(&mut self, mut range: Range) { + if range.is_empty() { + return; + } + if let Some(last_ri) = self.remove(&range) { + range.end = std::cmp::max(range.end, last_ri); + } + if let Some((_, ri)) = self.mp.range_mut(..range.start).next_back() { + if *ri >= range.start { + *ri = std::cmp::max(*ri, range.end); + return; + } + } + self.mp.insert(range.start, range.end); + } + + /// Removes a range from the container + /// + /// # Complexity + /// - Time: O(log n) ammortized + /// - Space: O(1) ammortized + pub fn remove_range(&mut self, range: Range) { + if range.is_empty() { + return; + } + if let Some(last_ri) = self.remove(&range) { + if range.end < last_ri { + self.mp.insert(range.end, last_ri); + } + } + if let Some((_, ri)) = self.mp.range_mut(..range.start).next_back() { + let ri = std::mem::replace(ri, std::cmp::min(*ri, range.start)); + if range.end < ri { + self.mp.insert(range.end, ri); + } + } + } + + /// Gets range containing idx + /// + /// # Complexity + /// - Time: O(log n) + /// - Space: O(1) + pub fn get_range(&self, idx: T) -> Option> { + if let Some((&le, &ri)) = self.mp.range(..=idx).next_back() { + if idx < ri { + return Some(le..ri); + } + } + None + } +} diff --git a/src/graphs/hld.rs b/src/graphs/hld.rs index 076a60d8..eb93a067 100644 --- a/src/graphs/hld.rs +++ b/src/graphs/hld.rs @@ -1,6 +1,7 @@ //! # Heavy Light Decomposition use crate::graphs::dfs_order::{get_dfs_postorder, get_dfs_preorder}; +use crate::monotonic::mono_st::mono_st; use std::ops::Range; /// # Example @@ -33,6 +34,8 @@ pub struct HLD { pub p: Vec>, /// time in pub tin: Vec, + /// depth + pub d: Vec, ord: Vec, siz: Vec, head: Vec, @@ -66,16 +69,19 @@ impl HLD { } let mut tin = vec![0; n]; let mut head = vec![0; n]; + let mut d = vec![0; n]; let ord = get_dfs_preorder(adj); for (i, &u) in ord.iter().enumerate() { tin[u] = i; for &v in &adj[u] { + d[v] = 1 + d[u]; head[v] = if v == adj[u][0] { head[u] } else { v }; } } HLD { p, siz, + d, ord, tin, head, @@ -92,7 +98,7 @@ impl HLD { let mut u_anc = false; loop { if self.tin[u] > self.tin[v] { - std::mem::swap(&mut u, &mut v); + (u, v) = (v, u); u_anc = !u_anc; } if self.head[u] == self.head[v] { @@ -124,7 +130,7 @@ impl HLD { pub fn lca(&self, mut u: usize, mut v: usize) -> usize { loop { if self.tin[u] > self.tin[v] { - std::mem::swap(&mut u, &mut v); + (u, v) = (v, u); } if self.head[u] == self.head[v] { return u; @@ -133,16 +139,13 @@ impl HLD { } } - /// If !vals_edges, then gets number of nodes on path from u to v - /// If vals_edges, then gets number of edges on path from u to v + /// Gets number of edges on path from u to v /// /// # Complexity /// - Time: O(log n) /// - Space: O(1) pub fn dist(&self, u: usize, v: usize) -> usize { - let mut dst = 0; - self.path(u, v, |range, _| dst += range.len()); - dst + self.d[u] + self.d[v] - 2 * self.d[self.lca(u, v)] } /// Returns true iff v is in u's subtree @@ -151,7 +154,7 @@ impl HLD { /// - Time: O(1) /// - Space: O(1) pub fn in_sub(&self, u: usize, v: usize) -> bool { - u == v || self.sub_tree(u).contains(&self.tin[v]) + (self.tin[u]..self.tin[u] + self.siz[u]).contains(&self.tin[v]) } /// Returns true iff w is on the path from u to v @@ -188,16 +191,53 @@ impl HLD { /// - Time: O(log n) /// - Space: O(1) pub fn kth_on_path(&self, u: usize, v: usize, k: usize) -> Option { - let mut dst_side = [0; 2]; - self.path(u, v, |range, u_anc| dst_side[u_anc as usize] += range.len()); - if k < dst_side[1] { - return self.kth_par(u, k); - } - let dst = dst_side[0] + dst_side[1] - !self.vals_edges as usize; - if k <= dst { - self.kth_par(v, dst - k) + let lca_d = self.d[self.lca(u, v)]; + let u_lca = self.d[u] - lca_d; + let v_lca = self.d[v] - lca_d; + if k <= u_lca { + self.kth_par(u, k) + } else if k <= u_lca + v_lca { + self.kth_par(v, u_lca + v_lca - k) } else { None } } + + /// # Auxiliary Tree + /// + /// - see + /// + /// # Example + /// ``` + /// use programming_team_code_rust::graphs::hld::HLD; + /// + /// let n = 5; + /// let mut adj = vec![vec![]; n]; + /// for (u, v) in [(0,1), (1,2), (2,3), (2,4)] { + /// adj[u].push(v); + /// adj[v].push(u); + /// } + /// + /// let hld = HLD::new(&mut adj, false); + /// + /// let (par, to_node) = hld.aux_tree(vec![0, 3, 4]); + /// // 0, 1, .., par.len()-1 is a topological/dfs order of aux tree + /// assert_eq!(par, [usize::MAX, 0, 1, 1]); + /// assert_eq!(to_node, [0, 2, 3, 4]); + /// ``` + /// + /// # Complexity + /// - k = nodes.len() + /// - Time: O((k log k) + (k log n)) + /// - Space: O(k) + pub fn aux_tree(&self, mut nodes: Vec) -> (Vec, Vec) { + nodes.sort_by(|&u, &v| self.tin[u].cmp(&self.tin[v])); + let siz = nodes.len(); + for i in 1..siz { + nodes.push(self.lca(nodes[i - 1], nodes[i])); + } + nodes.sort_by(|&u, &v| self.tin[u].cmp(&self.tin[v])); + nodes.dedup(); + (mono_st(&nodes, |&u, &v| self.in_sub(u, v)), nodes) + } } diff --git a/src/graphs/lca.rs b/src/graphs/lca.rs index 1305e17a..16adf1c3 100644 --- a/src/graphs/lca.rs +++ b/src/graphs/lca.rs @@ -84,7 +84,7 @@ impl LCA { } let (mut le, mut ri) = (self.tin[u], self.tin[v]); if le > ri { - std::mem::swap(&mut le, &mut ri); + (le, ri) = (ri, le); } self.p[self.rmq.query(le + 1..ri + 1).1].unwrap() } diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a96..00000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/strings/suf_ary.rs b/src/strings/suf_ary.rs index 52f87a00..addb7c43 100644 --- a/src/strings/suf_ary.rs +++ b/src/strings/suf_ary.rs @@ -110,7 +110,7 @@ impl SufAry { } let (mut le, mut ri) = (self.sa_inv[i1], self.sa_inv[i2]); if le > ri { - std::mem::swap(&mut le, &mut ri); + (le, ri) = (ri, le); } self.rmq.query(le..ri) }