Fenwick Tree

Given an integer array \(A\) of length \(n\), a Fenwick tree processes the following queries in \(O(\log{n})\) time:

  • Add a certain amount to an element
  • Calculate the sum of the elements of an interval

A Fenwick tree uses half the memory of a segment tree, but the performance in terms of time is just about the same.

A type of elements of \(A\) must be a primitive signed integer type, such as i32 and i64, and floats such as f64. Unsigned integer types like u64 do not work. Specifically, the type should implement From<i8>.

Example

fn main() {
let mut fw: Fenwick<i32> = Fenwick::new(10);
for i in 0..10 {
    print!("{} ", fw.get(i));
}
println!(); // 0 0 0 0 0 0 0 0 0 0
fw.add(2, 10);
fw.add(5, 100);
fw.add(3, -1);
for i in 0..10 {
    print!("{} ", fw.get(i));
}
println!(); // 0 0 10 -1 0 100 0 0 0 0
println!("{}", fw.sum(3..8)); // 99
}

struct Fenwick<T> {
    n: usize,
    data: Vec<T>,
}

impl<T: Copy + From<i8> + std::ops::AddAssign + std::ops::Sub<Output = T>> Fenwick<T> {
    fn new(n: usize) -> Self {
        Self {
            n,
            data: vec![0.into(); n],
        }
    }

    fn add(&mut self, idx: usize, val: T) {
        let mut idx = idx + 1;
        while idx <= self.n {
            self.data[idx - 1] += val;
            idx += idx & (!idx + 1);
        }
    }

    fn get(&self, idx: usize) -> T {
        self.sum(idx..=idx)
    }

    fn sum(&self, range: impl std::ops::RangeBounds<usize>) -> T {
        use std::ops::Bound::*;
        let l = match range.start_bound() {
            Included(&v) => v,
            Excluded(&v) => v + 1,
            Unbounded => 0,
        };
        let r = match range.end_bound() {
            Included(&v) => v + 1,
            Excluded(&v) => v,
            Unbounded => self.n,
        };
        self.inner_sum(r) - self.inner_sum(l)
    }

    fn inner_sum(&self, mut r: usize) -> T {
        let mut s: T = 0.into();
        while r > 0 {
            s += self.data[r - 1];
            r -= r & (!r + 1);
        }
        s
    }
}

Code

struct Fenwick<T> {
	n: usize,
	data: Vec<T>,
}

impl<T: Copy + From<i8> + std::ops::AddAssign + std::ops::Sub<Output = T>> Fenwick<T> {
	fn new(n: usize) -> Self {
		Self { n, data: vec![0.into(); n] }
	}

	fn add(&mut self, idx: usize, val: T) {
		let mut idx = idx + 1;
		while idx <= self.n {
			self.data[idx - 1] += val;
			idx += idx & (!idx + 1);
		}
	}

	fn get(&self, idx: usize) -> T {
		self.sum(idx..=idx)
	}

	fn sum(&self, range: impl std::ops::RangeBounds<usize>) -> T {
		use std::ops::Bound::*;
		let l = match range.start_bound() {
			Included(&v) => v,
			Excluded(&v) => v + 1,
			Unbounded => 0,
		};
		let r = match range.end_bound() {
			Included(&v) => v + 1,
			Excluded(&v) => v,
			Unbounded => self.n,
		};
		self.inner_sum(r) - self.inner_sum(l)
	}

	fn inner_sum(&self, mut r: usize) -> T {
		let mut s: T = 0.into();
		while r > 0 {
			s += self.data[r - 1];
			r -= r & (!r + 1);
		}
		s
	}
}