Welcome to the in-depth guide on Fenwick Trees! In this lesson, we'll explore what Fenwick Trees are, why they're important, and how to use them. Let's dive right in!
A Fenwick Tree, also known as a Binary Indexed Tree, is a data structure used for efficient range queries and updates on a sequence of numbers. Fenwick Trees can help us quickly answer questions like "What is the sum of all elements from index i to j?" or "Update the value at index i."
Fenwick Trees offer several advantages:
2n space, where n is the size of the input array, making them space-efficient compared to other solutions.A Fenwick Tree is built upon an array, where each index i represents a range ending at i. The value at index i stores the sum of elements from 0 to i.
Fenwick Tree: [3, 5, 7, 8, 10, 12, 15]
Array representation: [0, 3, 8, 15, 23, 35, 47]In the above example, the Fenwick Tree array represents the following:
Building a Fenwick Tree involves building the corresponding array and then populating it using the following formula:
array[i] = array[i] + array[(i + mask)]Here, mask is (i - 1) shifted to the right by 1. For example, if i is 3, then mask is (3 - 1) = 2, and (i + mask) is (3 + 2) = 5.
To update a value at index i, we first update the value at index i and then propagate the update to its ancestors using the same formula as above.
To find the sum of elements in a range [i, j], we simply find the sum of elements at index i, j, and all the intermediate indices (i + mask) where mask is (2^k - 1).
Fenwick Trees find applications in problems involving dynamic range sum queries and updates, such as:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int arr[N];
int ft[N];
void buildFenwickTree(int n) {
for (int i = 1; i <= n; i++) {
ft[i] = arr[i];
for (int j = i + (-i & i); j <= n; j += (j & -j)) {
ft[j] += arr[i];
}
}
}
int sumRange(int i, int j) {
int sum = 0;
for (int i_ = i; i_ <= j; i_ += (i_ & -i_)) {
sum += ft[i_];
}
return sum;
}
void update(int i, int val) {
for (int i_ = i; i <= N; i += (i & -i)) {
ft[i] += val - arr[i];
arr[i] = val;
}
}def build_fenwick_tree(arr):
n = len(arr)
ft = [0] * (n + 1)
for i in range(n):
ft[i] = arr[i]
for j in range(i + 1, n):
ft[j] += ft[j - i]
def sum_range(ft, i, j):
return sum(ft[x] for x in range(i, j + 1))
def update(ft, i, val):
for x in range(i, len(ft)):
ft[x] += val - ft[i]
arr[i] = valWhat is a Fenwick Tree used for?
Why is a Fenwick Tree space-efficient?