competitive_library/structure/
fenwick_tree.rs1pub trait Monoid {
4 type T: Clone;
5 fn identity_element() -> Self::T;
6 fn binary_operation(a: &Self::T, b: &Self::T) -> Self::T;
7}
8
9pub struct Add {}
10impl Monoid for Add {
11 type T = i64;
12 #[inline]
13 fn identity_element() -> Self::T {
14 0_i64
15 }
16 #[inline]
17 fn binary_operation(a: &Self::T, b: &Self::T) -> Self::T {
18 *a + *b
19 }
20}
21
22#[derive(Clone, Debug)]
24pub struct FenwickTree<M>
25where
26 M: Monoid,
27{
28 array: Vec<M::T>,
29}
30
31impl<M> FenwickTree<M>
32where
33 M: Monoid,
34{
35 #[inline]
36 pub fn new(size: usize) -> FenwickTree<M> {
37 Self {
38 array: vec![M::identity_element(); size + 1],
39 }
40 }
41
42 #[inline]
43 pub fn operate(&mut self, index: usize, x: M::T) {
44 let mut i = index + 1;
45 while i < self.array.len() {
46 self.array[i] = M::binary_operation(&self.array[i], &x);
47 i += i & i.wrapping_neg();
48 }
49 }
50
51 #[inline]
53 pub fn fold(&self, end: usize) -> M::T {
54 let mut s = M::identity_element();
55 let mut i = end;
56 while i > 0 {
57 s = M::binary_operation(&s, &self.array[i]);
58 i -= i & i.wrapping_neg();
59 }
60 s
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 #[test]
68 fn test_sum() {
69 let mut a = FenwickTree::<Add>::new(100);
70
71 (0..100).for_each(|i| a.operate(i, i as i64 + 1));
72
73 (0..100).for_each(|i| assert_eq!((1..=i).sum::<i64>(), a.fold(i as usize)));
74 }
75
76 pub struct Xor {}
77 impl Monoid for Xor {
78 type T = u64;
79 #[inline]
80 fn identity_element() -> Self::T {
81 0_u64
82 }
83 #[inline]
84 fn binary_operation(a: &Self::T, b: &Self::T) -> Self::T {
85 *a ^ *b
86 }
87 }
88 #[test]
89 fn test_xor() {
90 let a = [0, 5, 3, 4, 7, 0, 0, 0, 1, 0];
93 let txy_ans = vec![
94 (1, 10, 7, 0),
95 (2, 8, 9, 1),
96 (2, 3, 6, 0),
97 (2, 1, 6, 5),
98 (2, 1, 10, 3),
99 (1, 9, 4, 0),
100 (1, 6, 1, 0),
101 (1, 6, 3, 0),
102 (1, 1, 7, 0),
103 (2, 3, 5, 0),
104 ];
105
106 let mut ft = FenwickTree::<Xor>::new(10);
107
108 for (i, &v) in a.iter().enumerate() {
109 ft.operate(i, v);
110 }
111
112 for (t, x, y, ans) in txy_ans {
113 if t == 1 {
114 ft.operate(x as usize - 1, y);
115 } else {
116 assert_eq!(ft.fold(y as usize) ^ ft.fold(x as usize - 1), ans);
117 }
118 }
119 }
120}