-
Notifications
You must be signed in to change notification settings - Fork 225
/
Copy pathspecs.rs
126 lines (120 loc) · 4.75 KB
/
specs.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! A collection of example ArqSpec implementations
pub trait ArqSpec {
/// Type of underlying array elements.
type S: Clone;
/// Type of data representing an endomorphism.
// Note that while a Fn(S) -> S may seem like a more natural representation
// for an endomorphism, compositions would then have to delegate to each of
// their parts. This representation is more efficient.
type F: Clone;
/// Must satisfy the Associative Law:
/// For all a,b,c, op(a, op(b, c)) = op(op(a, b), c)
fn op(a: &Self::S, b: &Self::S) -> Self::S;
/// Must satisfy the Identity Law:
/// For all a, op(a, identity()) = op(identity(), a) = a
fn identity() -> Self::S;
/// Must satisfy the Composition Law:
/// For all f,g,a, apply(compose(f, g), a) = apply(f, apply(g, a))
fn compose(f: &Self::F, g: &Self::F) -> Self::F;
/// Must satisfy the Distributive Law:
/// For all f,a,b, apply(f, op(a, b), s+t) = op(apply(f, a, s), apply(f, b, t))
/// The `size` parameter makes this law easier to satisfy in certain cases.
fn apply(f: &Self::F, a: &Self::S, size: i64) -> Self::S;
// The following relaxations to the laws may apply.
// If only point updates are made, the Composition and Distributive Laws
// no longer apply.
// - compose() is never called, so it can be left unimplemented!().
// - apply() is only ever called on leaves, i.e., with size == 1.
// If only point queries are made, the Associative and Distributive Laws
// no longer apply.
// - op()'s result only matters when identity() is an argument.
// - apply()'s result only matters on leaves, i.e., with size == 1.
}
/// Range Minimum Query (RMQ), a classic application of ARQ.
/// update(l, r, &f) sets all entries a[l..=r] to f.
/// query(l, r) finds the minimum value in a[l..=r].
//
// Exercises: try augmenting this struct to find the index of a minimum element
// in a range query, as well as the number of elements equal to the minimum.
// Then instead of overwriting values with a constant assignment a[i] = f,
// try supporting addition: a[i] += f.
pub enum AssignMin {}
impl ArqSpec for AssignMin {
type S = i64;
type F = i64;
fn op(&a: &Self::S, &b: &Self::S) -> Self::S {
a.min(b)
}
fn identity() -> Self::S {
i64::MAX
}
fn compose(&f: &Self::F, _: &Self::F) -> Self::F {
f
}
fn apply(&f: &Self::F, _: &Self::S, _: i64) -> Self::S {
f
}
}
/// Range Sum Query, a slightly trickier classic application of ARQ.
/// update(l, r, &f) sets all entries a[l..=r] to f.
/// query(l, r) sums all the entries a[l..=r].
///
/// # Panics
///
/// Associated functions will panic on overflow.
//
// Note that while the `size` parameter seems necessary to satisfy the
// Distributive Law, it is merely a convenience: in essence what we've done
// is move to the product monoid of tuples (value, size_of_subtree).
//
// In mathematical jargon, we say that constant assignment f(a) = f is not an
// endomorphism on (i64, +) because f(a+b) = f != 2*f = f(a) + f(b).
// On the other hand, f((a, s)) = (f*s, s) is indeed an endomorphism on pairs
// with vector addition: f((a, s) + (b, t)) = f((a+b, s+t)) = (f*(s+t), s+t)
// = (f*s, s) + (f*t, t) = f((a,s)) + f((b,t)).
pub enum AssignSum {}
impl ArqSpec for AssignSum {
type S = i64;
type F = i64;
fn op(&a: &Self::S, &b: &Self::S) -> Self::S {
a + b
}
fn identity() -> Self::S {
0
}
fn compose(&f: &Self::F, _: &Self::F) -> Self::F {
f
}
fn apply(&f: &Self::F, _: &Self::S, size: i64) -> Self::S {
f * size
}
}
/// Supply & Demand, based on https://codeforces.com/gym/102218/problem/F
/// update(i, i, &(p, o)) increases supply by p and demand by o at time i.
/// query(l, r) computes total supply and demand at times l to r, as well as
// how much of the supply is subsequently met by the demand.
//
// Note that the apply() operation is only correct when applied to leaf nodes.
// Therefore, update() must only be used in "eager" mode, i.e., with l == r.
// compose() should be unimplemented!() to prevent accidental "lazy" updates.
pub enum SupplyDemand {}
impl ArqSpec for SupplyDemand {
type S = (i64, i64, i64); // production, orders, sales
type F = (i64, i64);
fn op((p1, o1, s1): &Self::S, (p2, o2, s2): &Self::S) -> Self::S {
let extra = (p1 - s1).min(o2 - s2);
(p1 + p2, o1 + o2, s1 + s2 + extra)
}
fn identity() -> Self::S {
(0, 0, 0)
}
fn compose(_: &Self::F, _: &Self::F) -> Self::F {
unimplemented!()
}
fn apply(&(p_add, o_add): &Self::F, &(p, o, _): &Self::S, s: i64) -> Self::S {
assert_eq!(s, 1);
let p = p + p_add;
let o = o + o_add;
(p, o, p.min(o))
}
}