Skip to content

Commit f5c3543

Browse files
committed
coordinate compression and ArqSpec documentation on point queries
1 parent fb0a9ed commit f5c3543

File tree

3 files changed

+60
-9
lines changed

3 files changed

+60
-9
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ Rather than try to persuade you with words, this repository aims to show by exam
4444
## Contents
4545

4646
- [Basic graph representations](src/graph/mod.rs): adjacency lists, disjoint set union
47-
- [Elementary Graph algorithms](src/graph/util.rs): minimum spanning tree, Euler path, Dijkstra's algorithm, DFS iteration
47+
- [Elementary graph algorithms](src/graph/util.rs): minimum spanning tree, Euler path, Dijkstra's algorithm, DFS iteration
4848
- [Network flows](src/graph/flow.rs): Dinic's blocking flow, Hopcroft-Karp bipartite matching, min cost max flow
4949
- [Connected components](src/graph/connectivity.rs): 2-edge-, 2-vertex- and strongly connected components, bridges, articulation points, topological sort, 2-SAT
50-
- [Associative range query](src/range_query): known colloquially as *segtrees*, and Mo's query square root decomposition
51-
- [GCD Math](src/math/mod.rs): canonical solution to Bezout's identity
50+
- [Associative range query](src/range_query): known colloquially as *segtrees*, coordinate compression, and Mo's query square root decomposition
51+
- [Number thery](src/math/mod.rs): canonical solution to Bezout's identity, Miller's primality test
5252
- [Arithmetic](src/math/num.rs): rational and complex numbers, linear algebra, safe modular arithmetic
5353
- [FFT](src/math/fft.rs): fast Fourier transform, number theoretic transform, convolution
5454
- [Scanner](src/scanner.rs): utility for reading input data ergonomically

src/range_query/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,53 @@ pub use dynamic_arq::{ArqView, DynamicArq};
66
pub use specs::ArqSpec;
77
pub use static_arq::StaticArq;
88

9+
/// A simple data structure for coordinate compression
10+
pub struct SparseIndex {
11+
coords: Vec<i64>
12+
}
13+
14+
impl SparseIndex {
15+
/// Build an index, given the full set of coordinates to compress.
16+
pub fn new(mut coords: Vec<i64>) -> Self {
17+
coords.sort_unstable();
18+
coords.dedup();
19+
Self { coords }
20+
}
21+
22+
/// Return Ok(i) if the coordinate q appears at index i
23+
/// Return Err(i) if q appears between indices i-1 and i
24+
pub fn compress(&self, q: i64) -> Result<usize, usize> {
25+
self.coords.binary_search(&q)
26+
}
27+
}
28+
929
#[cfg(test)]
1030
mod test {
1131
use super::specs::*;
1232
use super::*;
1333

34+
#[test]
35+
fn test_coord_compress() {
36+
let mut coords = vec![16, 99, 45, 18];
37+
let index = SparseIndex::new(coords.clone());
38+
39+
coords.sort_unstable();
40+
for (i, q) in coords.into_iter().enumerate() {
41+
assert_eq!(index.compress(q - 1), Err(i));
42+
assert_eq!(index.compress(q), Ok(i));
43+
assert_eq!(index.compress(q + 1), Err(i + 1));
44+
}
45+
}
46+
47+
#[test]
48+
fn test_range_compress() {
49+
let queries = vec![(0, 10), (10, 19), (20, 29)];
50+
let coords = queries.iter().flat_map(|&(i, j)| vec![i, j + 1]).collect();
51+
let index = SparseIndex::new(coords);
52+
53+
assert_eq!(index.coords, vec![0, 10, 11, 20, 30]);
54+
}
55+
1456
#[test]
1557
fn test_rmq() {
1658
let mut arq = StaticArq::<AssignMin>::new(&[0; 10]);

src/range_query/specs.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,23 @@ pub trait ArqSpec {
1515
/// Must satisfy the Identity Law:
1616
/// For all a, op(a, identity()) = op(identity(), a) = a
1717
fn identity() -> Self::S;
18-
/// For point query / eager updates, compose() can be unimplemented!()
19-
/// For range query / lazy updates, it must satisfy the Composition Law:
18+
/// Must satisfy the Composition Law:
2019
/// For all f,g,a, apply(compose(f, g), a) = apply(f, apply(g, a))
2120
fn compose(f: &Self::F, g: &Self::F) -> Self::F;
22-
/// For point query / eager updates, apply() can assume it acts on a leaf.
23-
/// For range query / lazy updates, it must satisfy the Distributive Law:
24-
/// For all f,a,b, apply(f, op(a, b)) = op(apply(f, a), apply(f, b))
21+
/// Must satisfy the Distributive Law:
22+
/// For all f,a,b, apply(f, op(a, b), s+t) = op(apply(f, a, s), apply(f, b, t))
2523
/// The `size` parameter makes this law easier to satisfy in certain cases.
2624
fn apply(f: &Self::F, a: &Self::S, size: i64) -> Self::S;
25+
26+
// The following relaxations to the laws may apply.
27+
// If only point updates are made, the Composition and Distributive Laws
28+
// no longer apply.
29+
// - compose() is never called, so it can be left unimplemented!().
30+
// - apply() is only ever called on leaves, i.e., with size == 1.
31+
// If only point queries are made, the Associative and Distributive Laws
32+
// no longer apply.
33+
// - op()'s result only matters when identity() is an argument.
34+
// - apply()'s result only matters on leaves, i.e., with size == 1.
2735
}
2836

2937
/// Range Minimum Query (RMQ), a classic application of ARQ.
@@ -109,7 +117,8 @@ impl ArqSpec for SupplyDemand {
109117
fn compose(_: &Self::F, _: &Self::F) -> Self::F {
110118
unimplemented!()
111119
}
112-
fn apply(&(p_add, o_add): &Self::F, &(p, o, _): &Self::S, _: i64) -> Self::S {
120+
fn apply(&(p_add, o_add): &Self::F, &(p, o, _): &Self::S, s: i64) -> Self::S {
121+
assert_eq!(s, 1);
113122
let p = p + p_add;
114123
let o = o + o_add;
115124
(p, o, p.min(o))

0 commit comments

Comments
 (0)