From b2968ff62ac792fc920a048465db6c59797f8fbe Mon Sep 17 00:00:00 2001 From: Naman Garg <66401604+namanlp@users.noreply.github.com> Date: Thu, 9 Mar 2023 03:34:40 +0000 Subject: [PATCH 1/3] Add Codechef to supported websites (#25) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cae59f9..be5b5d9 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ To my delight, I found that Rust eliminates entire classes of bugs, while reduci Some contest sites and online judges that support Rust: - [Codeforces](https://codeforces.com) +- [CodeChef](https://www.codechef.com) - [AtCoder](https://atcoder.jp) - [Kattis](https://open.kattis.com/help/rust) - [SPOJ](https://www.spoj.com/) From 6c5d5444e7ea952166b4aa15f293ace36106123f Mon Sep 17 00:00:00 2001 From: Fr0benius Date: Sun, 19 Mar 2023 16:25:37 -0700 Subject: [PATCH 2/3] Li Chao tree (#16) A second data structure for maintaining the maximum of a set of lines ("convex hull trick"), implemented by @Fr0benius. --- src/li_chao.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 111 insertions(+) create mode 100644 src/li_chao.rs diff --git a/src/li_chao.rs b/src/li_chao.rs new file mode 100644 index 0000000..f69a0ae --- /dev/null +++ b/src/li_chao.rs @@ -0,0 +1,110 @@ +/// A structure for answering maximum queries on a set of linear functions. Supports two +/// operations: inserting a linear function and querying for maximum at a given point. +/// The queries can be done in any order, and we can do all the calculations using integers. +/// https://cp-algorithms.com/geometry/convex_hull_trick.html#li-chao-tree +/// Compared to the code in the above link, this implementation further improves the algorithm by +/// reducing the number of nodes to (right - left). This is done by removing the midpoint of a +/// segment from both children. Even better, this allows the index of a node to just be the +/// midpoint of the interval! + +/// Just like normal segment trees, this could be modified to a dynamic tree when the range is +/// huge, or if the queries are known in advance the x-coordinates can be compressed. +/// (it can also be made persistent!). + +pub struct LiChaoTree { + left: i64, + right: i64, + lines: Vec<(i64, i64)>, +} + +impl LiChaoTree { + /// Creates a new tree, built to handle queries on the interval [left, right). + pub fn new(left: i64, right: i64) -> Self { + Self { + left, + right, + lines: vec![(0, std::i64::MIN); (right - left) as usize], + } + } + + /// Every node in the tree has the property that the line that maximizes its midpoint is found + /// either in the node or one of its ancestors. When we visit a node, we compute the winner at + /// the midpoint of the node. The winner is stored in the node. The loser can still possibly + /// beat the winner on some segment, either to the left or to the right of the current + /// midpoint, so we propagate it to that segment. This sequence ensures that the invariant is + /// kept. + fn max_with_impl(&mut self, mut m: i64, mut b: i64, l: i64, r: i64) { + if r <= l { + return; + } + let ix = ((r - self.left + l - self.left) / 2) as usize; + let mid = self.left + (ix as i64); + let (ref mut m_ix, ref mut b_ix) = self.lines[ix]; + if m * mid + b > *m_ix * mid + *b_ix { + std::mem::swap(&mut m, m_ix); + std::mem::swap(&mut b, b_ix); + } + if m < *m_ix { + self.max_with_impl(m, b, l, mid); + } else if m > *m_ix { + self.max_with_impl(m, b, mid + 1, r); + } + } + + /// Adds the line with slope m and intercept b. O(log N) complexity. + pub fn max_with(&mut self, m: i64, b: i64) { + self.max_with_impl(m, b, self.left, self.right); + } + + /// Because of the invariant established by add_line, we know that the best line for a given + /// point is stored in one of the ancestors of its node. So we accumulate the maximum answer as + /// we go back up the tree. + fn evaluate_impl(&self, x: i64, l: i64, r: i64) -> i64 { + if r == l { + return i64::MIN; + } + let ix = ((r - self.left + l - self.left) / 2) as usize; + let mid = ix as i64 + self.left; + let y = self.lines[ix].0 * x + self.lines[ix].1; + if x == mid { + y + } else if x < mid { + self.evaluate_impl(x, l, mid).max(y) + } else { + self.evaluate_impl(x, mid + 1, r).max(y) + } + } + + /// Finds the maximum mx+b among all lines in the structure. O(log N) complexity. + pub fn evaluate(&self, x: i64) -> i64 { + self.evaluate_impl(x, self.left, self.right) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_li_chao_tree() { + let lines = [(0, -3), (-1, 0), (1, -8), (-2, 1), (1, -4)]; + let xs = [0, 1, 2, 3, 4, 5]; + // results[i] consists of the expected y-coordinates after processing + // the first i+1 lines. + let results = [ + [-3, -3, -3, -3, -3, -3], + [0, -1, -2, -3, -3, -3], + [0, -1, -2, -3, -3, -3], + [1, -1, -2, -3, -3, -3], + [1, -1, -2, -1, 0, 1], + ]; + let mut li_chao = LiChaoTree::new(0, 6); + + assert_eq!(li_chao.evaluate(0), std::i64::MIN); + for (&(slope, intercept), expected) in lines.iter().zip(results.iter()) { + li_chao.max_with(slope, intercept); + let ys: Vec = xs.iter().map(|&x| li_chao.evaluate(x)).collect(); + assert_eq!(expected, &ys[..]); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 6a96038..ba482d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod caching; pub mod graph; +pub mod li_chao; pub mod math; pub mod order; pub mod range_query; From 2073670c540935960849f365e1895f558fa4319d Mon Sep 17 00:00:00 2001 From: Aram Ebtekar Date: Thu, 27 Feb 2025 12:20:03 -0800 Subject: [PATCH 3/3] Rust 2024 edition --- Cargo.toml | 4 ++-- README.md | 5 +---- src/graph/flow.rs | 2 +- src/graph/mod.rs | 2 +- src/graph/util.rs | 10 +++++----- src/li_chao.rs | 9 ++++----- src/math/mod.rs | 6 +----- src/range_query/dynamic_arq.rs | 4 ++-- src/range_query/specs.rs | 2 +- src/range_query/static_arq.rs | 6 +++--- src/string_proc.rs | 2 +- tests/codeforces343d.rs | 2 +- 12 files changed, 23 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ef526b1..ae11d8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "contest-algorithms" -version = "0.3.1-alpha.0" +version = "0.3.1-alpha.1" authors = ["Aram Ebtekar"] -edition = "2021" +edition = "2024" description = "Common algorithms and data structures for programming contests" repository = "https://github.com/EbTech/rust-algorithms" diff --git a/README.md b/README.md index be5b5d9..2add26f 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,7 @@ Some contest sites and online judges that support Rust: - [HackerRank](https://www.hackerrank.com/contests) - [Timus](http://acm.timus.ru/help.aspx?topic=rust) -The following support pre-2018 versions of Rust: -- [Google Kick Start and Code Jam](https://codingcompetitions.withgoogle.com) - -For help in getting started, you may check out [some of my past submissions](https://codeforces.com/contest/1168/submission/55200038). +For help in getting started, you may check out [some of my past submissions](https://codeforces.com/contest/1168/submission/55200038) (requires login). ## Programming Language Advocacy diff --git a/src/graph/flow.rs b/src/graph/flow.rs index 0b6e684..41af65a 100644 --- a/src/graph/flow.rs +++ b/src/graph/flow.rs @@ -143,7 +143,7 @@ impl FlowGraph { let (mut min_cost, mut max_flow) = (0, 0); loop { let par = self.mcf_search(s, &flow, &mut pot); - if par[t] == None { + if par[t].is_none() { break; } let (dc, df) = self.mcf_augment(t, &par, &mut flow); diff --git a/src/graph/mod.rs b/src/graph/mod.rs index 41d8e30..f5a4c9e 100644 --- a/src/graph/mod.rs +++ b/src/graph/mod.rs @@ -111,7 +111,7 @@ pub struct AdjListIterator<'a> { next_e: Option, } -impl<'a> Iterator for AdjListIterator<'a> { +impl Iterator for AdjListIterator<'_> { type Item = (usize, usize); /// Produces an outgoing edge and vertex. diff --git a/src/graph/util.rs b/src/graph/util.rs index b7a3817..bf38f19 100644 --- a/src/graph/util.rs +++ b/src/graph/util.rs @@ -12,16 +12,16 @@ impl Graph { .map(|u| self.adj_list(u)) .collect::>(); let mut edges = Vec::with_capacity(self.num_e()); - self.euler_recurse(u, &mut adj_iters, &mut edges); + Self::euler_recurse(u, &mut adj_iters, &mut edges); edges.reverse(); edges } // Helper function used by euler_path. Note that we can't use a for-loop // that would consume the adjacency list as recursive calls may need it. - fn euler_recurse(&self, u: usize, adj: &mut [AdjListIterator], edges: &mut Vec) { + fn euler_recurse(u: usize, adj: &mut [AdjListIterator], edges: &mut Vec) { while let Some((e, v)) = adj[u].next() { - self.euler_recurse(v, adj, edges); + Self::euler_recurse(v, adj, edges); edges.push(e); } } @@ -42,7 +42,7 @@ impl Graph { // Single-source shortest paths on a directed graph with non-negative weights pub fn dijkstra(&self, weights: &[u64], u: usize) -> Vec { assert_eq!(self.num_e(), weights.len()); - let mut dist = vec![u64::max_value(); weights.len()]; + let mut dist = vec![u64::MAX; weights.len()]; let mut heap = std::collections::BinaryHeap::new(); dist[u] = 0; @@ -82,7 +82,7 @@ pub struct DfsIterator<'a> { adj_iters: Vec>, } -impl<'a> Iterator for DfsIterator<'a> { +impl Iterator for DfsIterator<'_> { type Item = (usize, usize); /// Returns next edge and vertex in the depth-first traversal diff --git a/src/li_chao.rs b/src/li_chao.rs index f69a0ae..39cbb74 100644 --- a/src/li_chao.rs +++ b/src/li_chao.rs @@ -1,16 +1,15 @@ /// A structure for answering maximum queries on a set of linear functions. Supports two -/// operations: inserting a linear function and querying for maximum at a given point. +/// operations: inserting a linear function and querying for maximum at a given point. /// The queries can be done in any order, and we can do all the calculations using integers. /// https://cp-algorithms.com/geometry/convex_hull_trick.html#li-chao-tree /// Compared to the code in the above link, this implementation further improves the algorithm by /// reducing the number of nodes to (right - left). This is done by removing the midpoint of a /// segment from both children. Even better, this allows the index of a node to just be the /// midpoint of the interval! - +/// /// Just like normal segment trees, this could be modified to a dynamic tree when the range is /// huge, or if the queries are known in advance the x-coordinates can be compressed. /// (it can also be made persistent!). - pub struct LiChaoTree { left: i64, right: i64, @@ -23,7 +22,7 @@ impl LiChaoTree { Self { left, right, - lines: vec![(0, std::i64::MIN); (right - left) as usize], + lines: vec![(0, i64::MIN); (right - left) as usize], } } @@ -100,7 +99,7 @@ mod test { ]; let mut li_chao = LiChaoTree::new(0, 6); - assert_eq!(li_chao.evaluate(0), std::i64::MIN); + assert_eq!(li_chao.evaluate(0), i64::MIN); for (&(slope, intercept), expected) in lines.iter().zip(results.iter()) { li_chao.max_with(slope, intercept); let ys: Vec = xs.iter().map(|&x| li_chao.evaluate(x)).collect(); diff --git a/src/math/mod.rs b/src/math/mod.rs index 42127cc..c27e7af 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -31,11 +31,7 @@ pub fn canon_egcd(a: i64, b: i64, c: i64) -> Option<(i64, i64, i64)> { // TODO: deduplicate modular arithmetic code with num::Field fn pos_mod(n: i64, m: i64) -> i64 { - if n < 0 { - n + m - } else { - n - } + if n < 0 { n + m } else { n } } fn mod_mul(a: i64, b: i64, m: i64) -> i64 { pos_mod((a as i128 * b as i128 % m as i128) as i64, m) diff --git a/src/range_query/dynamic_arq.rs b/src/range_query/dynamic_arq.rs index f33eaaf..6450468 100644 --- a/src/range_query/dynamic_arq.rs +++ b/src/range_query/dynamic_arq.rs @@ -24,7 +24,7 @@ impl Default for DynamicArqNode { Self { val: T::identity(), app: None, - down: (usize::max_value(), usize::max_value()), + down: (usize::MAX, usize::MAX), } } } @@ -97,7 +97,7 @@ impl DynamicArq { } pub fn push(&mut self, (p, s): ArqView) -> (ArqView, ArqView) { - if self.nodes[p].down.0 == usize::max_value() { + if self.nodes[p].down.0 == usize::MAX { self.nodes.push(DynamicArqNode::default()); self.nodes.push(DynamicArqNode::default()); self.nodes[p].down = (self.nodes.len() - 2, self.nodes.len() - 1) diff --git a/src/range_query/specs.rs b/src/range_query/specs.rs index 1340a4c..9a70411 100644 --- a/src/range_query/specs.rs +++ b/src/range_query/specs.rs @@ -50,7 +50,7 @@ impl ArqSpec for AssignMin { a.min(b) } fn identity() -> Self::S { - i64::max_value() + i64::MAX } fn compose(&f: &Self::F, _: &Self::F) -> Self::F { f diff --git a/src/range_query/static_arq.rs b/src/range_query/static_arq.rs index 14a9331..461986d 100644 --- a/src/range_query/static_arq.rs +++ b/src/range_query/static_arq.rs @@ -50,14 +50,14 @@ impl StaticArq { fn push(&mut self, p: usize) { if let Some(ref f) = self.app[p].take() { - let s = ((self.app.len() + p - 1) / p / 2).next_power_of_two() as i64; + let s = (self.app.len().div_ceil(p) / 2).next_power_of_two() as i64; self.apply(p << 1, f, s); - self.apply(p << 1 | 1, f, s); + self.apply((p << 1) | 1, f, s); } } fn pull(&mut self, p: usize) { - self.val[p] = T::op(&self.val[p << 1], &self.val[p << 1 | 1]); + self.val[p] = T::op(&self.val[p << 1], &self.val[(p << 1) | 1]); } fn push_to(&mut self, p: usize) { diff --git a/src/string_proc.rs b/src/string_proc.rs index 888bf67..4716f68 100644 --- a/src/string_proc.rs +++ b/src/string_proc.rs @@ -1,6 +1,6 @@ //! String processing algorithms. use std::cmp::{max, min}; -use std::collections::{hash_map::Entry, HashMap, VecDeque}; +use std::collections::{HashMap, VecDeque, hash_map::Entry}; /// Prefix trie, easily augmentable by adding more fields and/or methods pub struct Trie { diff --git a/tests/codeforces343d.rs b/tests/codeforces343d.rs index 94b911a..ec0f447 100644 --- a/tests/codeforces343d.rs +++ b/tests/codeforces343d.rs @@ -4,7 +4,7 @@ //! Also, use the commented code in main() to employ standard I/O. extern crate contest_algorithms; use contest_algorithms::graph::Graph; -use contest_algorithms::range_query::{specs::AssignSum, StaticArq}; +use contest_algorithms::range_query::{StaticArq, specs::AssignSum}; use contest_algorithms::scanner::Scanner; use std::io; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy