Skip to content

Commit 72524d7

Browse files
committed
Preliminary implementation of a generic ArqTree
1 parent d8ab73b commit 72524d7

File tree

1 file changed

+70
-34
lines changed

1 file changed

+70
-34
lines changed

src/arq_tree.rs

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,62 @@
77
///
88
/// - modify(l, r, f) replaces a_i (l <= i <= r) by f(a_i) for a homomorphism f
99
/// - query(l, r) returns the aggregate a_l + a_{l+1} + ... + a_r
10-
///
11-
/// To customize, simply change the commented lines.
12-
/// In this example, we chose to support range sum queries and range constant
13-
/// assignments. Since constant assignment f_c(a) = c is not a homomorphism over
14-
/// integers, we have to augment the monoid type, using the 2D vector (a_i, 1)
15-
/// instead of a_i. You may check that f_c((a, s)) = (c*s, s) is a homomorphism.
16-
pub struct ArqTree {
17-
d: Vec<Option<i64>>,
18-
t: Vec<i64>,
19-
s: Vec<i64>,
10+
pub struct ArqTree<T: ArqSpec> {
11+
d: Vec<Option<T::H>>,
12+
t: Vec<T::M>,
2013
}
2114

22-
impl ArqTree {
23-
/// Initializes a sequence of identity elements.
24-
pub fn new(size: usize) -> Self {
25-
let mut s = vec![1; 2 * size];
15+
impl<T: ArqSpec> ArqTree<T>
16+
where
17+
T::H: Clone,
18+
{
19+
/// Initializes a static balanced tree on top of the given sequence.
20+
pub fn new(mut init: Vec<T::M>) -> Self {
21+
let size = init.len();
22+
let mut t = (0..size).map(|_| T::identity()).collect::<Vec<_>>();
23+
t.append(&mut init);
2624
for i in (0..size).rev() {
27-
s[i] = s[i << 1] + s[i << 1 | 1];
25+
t[i] = T::op(&t[i << 1], &t[i << 1 | 1]);
2826
}
2927
Self {
30-
d: vec![None; size],
31-
t: vec![0; 2 * size], // monoid identity
32-
s: s,
28+
d: (0..size).map(|_| None).collect(),
29+
t: t,
3330
}
3431
}
3532

36-
fn apply(&mut self, p: usize, f: i64) {
37-
self.t[p] = f * self.s[p]; // hom application
33+
fn apply(&mut self, p: usize, f: &T::H) {
34+
self.t[p] = T::apply(f, &self.t[p]); // hom application
3835
if p < self.d.len() {
39-
self.d[p] = Some(f); // hom composition
36+
let h = if let Some(ref g) = self.d[p] {
37+
T::compose(f, g)
38+
} else {
39+
f.clone()
40+
};
41+
self.d[p] = Some(h);
4042
}
4143
}
4244

4345
fn push(&mut self, p: usize) {
4446
for s in (1..32).rev() {
4547
let i = p >> s;
46-
if let Some(f) = self.d[i] {
48+
if let Some(ref f) = self.d[i].take() {
4749
self.apply(i << 1, f);
4850
self.apply(i << 1 | 1, f);
49-
self.d[i] = None;
5051
}
5152
}
5253
}
5354

5455
fn pull(&mut self, mut p: usize) {
5556
while p > 1 {
5657
p >>= 1;
57-
if self.d[p] == None {
58-
self.t[p] = self.t[p << 1] + self.t[p << 1 | 1]; // monoid op
58+
if self.d[p].is_none() {
59+
self.t[p] = T::op(&self.t[p << 1], &self.t[p << 1 | 1]); // monoid op
5960
}
6061
}
6162
}
6263

6364
/// Performs the homomorphism f on all entries from l to r, inclusive.
64-
pub fn modify(&mut self, mut l: usize, mut r: usize, f: i64) {
65+
pub fn modify(&mut self, mut l: usize, mut r: usize, f: &T::H) {
6566
l += self.d.len();
6667
r += self.d.len();
6768
let (l0, r0) = (l, r);
@@ -84,19 +85,19 @@ impl ArqTree {
8485
}
8586

8687
/// Returns the aggregate range query on all entries from l to r, inclusive.
87-
pub fn query(&mut self, mut l: usize, mut r: usize) -> i64 {
88+
pub fn query(&mut self, mut l: usize, mut r: usize) -> T::M {
8889
l += self.d.len();
8990
r += self.d.len();
9091
self.push(l);
9192
self.push(r);
92-
let mut res = 0; // monoid identity
93+
let mut res = T::identity(); // monoid identity
9394
while l <= r {
9495
if l & 1 == 1 {
95-
res = res + self.t[l]; // monoid op
96+
res = T::op(&res, &self.t[l]); // monoid op
9697
l += 1;
9798
}
9899
if r & 1 == 0 {
99-
res = self.t[r] + res; // monoid op
100+
res = T::op(&self.t[r], &res); // monoid op
100101
r -= 1;
101102
}
102103
l >>= 1;
@@ -106,17 +107,52 @@ impl ArqTree {
106107
}
107108
}
108109

110+
pub trait ArqSpec {
111+
type H;
112+
type M;
113+
fn compose(f: &Self::H, g: &Self::H) -> Self::H;
114+
fn apply(f: &Self::H, a: &Self::M) -> Self::M;
115+
fn op(a: &Self::M, b: &Self::M) -> Self::M;
116+
fn identity() -> Self::M;
117+
}
118+
119+
/// In this example, we chose to support range sum queries and range constant
120+
/// assignments. Since constant assignment f_c(a) = c is not a homomorphism over
121+
/// integers, we have to augment the monoid type, using the 2D vector (a_i, 1)
122+
/// instead of a_i. You may check that f_c((a, s)) = (c*s, s) is a homomorphism.
123+
pub struct AssignAdd;
124+
125+
impl ArqSpec for AssignAdd {
126+
type H = i64;
127+
type M = (i64, i64);
128+
fn compose(f: &Self::H, _: &Self::H) -> Self::H {
129+
*f
130+
}
131+
fn apply(f: &Self::H, a: &Self::M) -> Self::M {
132+
(f * a.1, a.1)
133+
}
134+
fn op(a: &Self::M, b: &Self::M) -> Self::M {
135+
(a.0 + b.0, a.1 + b.1)
136+
}
137+
fn identity() -> Self::M {
138+
(0, 0)
139+
}
140+
}
141+
142+
109143
#[cfg(test)]
110144
mod test {
111145
use super::*;
112146

113147
#[test]
114148
fn test_arq_tree() {
115-
let mut arq = ArqTree::new(10);
149+
let mut arq = ArqTree::<AssignAdd>::new(vec![(0, 1); 10]);
150+
151+
assert_eq!(arq.query(0, 9), (0, 10));
116152

117-
arq.modify(1, 3, 10);
118-
arq.modify(3, 5, 1);
153+
arq.modify(1, 3, &10);
154+
arq.modify(3, 5, &1);
119155

120-
assert_eq!(arq.query(0, 9), 23);
156+
assert_eq!(arq.query(0, 9), (23, 10));
121157
}
122158
}

0 commit comments

Comments
 (0)