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_value() } 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)) } }