Femwick Tree / Binary Indexed Tree
Introduction
Where is it used?
Consider a problem where you have an array of numbers with length upto 1e6 and you have to perform two types of queries:
Update the value at a particular index.
Find the sum of all elements from index l to a particular index.
This can be done using a Fenwick Tree in O(logn) time complexity.
What is it?
A Fenwick Tree is a data structure that can efficiently update elements and calculate prefix sums in a table of numbers.
It is also known as a Binary Indexed Tree (BIT).
Some Background
BIT uses one-based indexing.
Calculating the Rightmost Set Bit:
The rightmost set bit of a number can be calculated using the formula
x & -x.Example:
x = 10 (1010), then-x = -10 = 2's complement of 10 = complement of(10) + 1 = 0101 + 1 = (0110)andx & -x = (0010)which is the rightmost set bit.
Removing the Rightmost Set Bit:
The rightmost set bit of a number can be removed using the formula
x = x - (x & -x).Example:
x = 10 (1010), thenx & -x = (0010)andx - (x & -x) = 10 - 2 = 8.
Construction
What Fenwick Tree Represents?
Consider an array
arrof lengthnand a Fenwick Tree or arrayBITof lengthn+1.Every index of the BIT array represents the sum of elements from a particular range.
The index
iof the BIT array represents the sum of elements from indexj to iof the original arrayarr.Index
jcan be calculated by removing the rightmost set bit from the indexiand adding 1 to it, Thereforej = i - (i & -i) + 1.
Example:
Consider an array
arr = [1, 2, 3, 4, 5, 6, 7, 8]and a BIT array of size 9BIT = [0, 0, 0, 0, 0, 0, 0, 0, 0].The BIT array will be updated as follows:
Array is onebased Indexed aswell the BIT
BIT[1] = sum of elements from index 1 to 1 = 1BIT[2] = sum of elements from index 1 to 2 = 3BIT[3] = sum of elements from index 3 to 3 = 3BIT[4] = sum of elements from index 1 to 4 = 10BIT[5] = sum of elements from index 5 to 5 = 5BIT[6] = sum of elements from index 5 to 6 = 11BIT[7] = sum of elements from index 7 to 7 = 7BIT[8] = sum of elements from index 1 to 8 = 36The BIT array will look like this:
BIT = [0, 1, 3, 3, 10, 5, 11, 7, 36].
Now What to Do With BIT.
Querying
If we want to find the sum of elements from index 1 to 5, we can calculate it by :
Start from index 5 and keep removing the rightmost set bit and adding the BIT[i] value at that index to the sum.
Sum will represent the sum of elements from index 1 to 5.
i.e.
sum = BIT[5] + BIT[4] + BIT[0] = 5 + 10 + 0 = 15Which is the sum of elements from index 1 to 5, (1 + 2 + 3 + 4 + 5 = 15).
int query(int index){ int sum = 0; while(index > 0){ sum += BIT[index]; index = index - (index & -index); } return sum; }The time complexity of querying is O(logn).
So the sum of elements from index
ltorcan be calculated bysum = query(r) - query(l-1).
Updating
Now Think like you have created BIT , and you want to update the value at index
ibyvalupdating means addingvalto the value at indexiand updating the BIT array accordingly.To update the BIT array , Since, BIT array stores the sum of elements prior to that index, so updating the value at any index will affect the BIT array at that index and indexes after that index which contains sum which indcludes that element of array.
So, to find the indexes which will be affected by updating the value at index
i, we can calculate the indexes by adding the rightmost set bit to the indexiand updating the BIT array at that index.Example:
Consider the array
arr = [1, 2, 3, 4, 5, 6, 7, 8]and the BIT arrayBIT = [0, 1, 3, 3, 10, 5, 11, 7, 36].If we want to update the value at index 5 by 2, then the BIT array will be updated as follows:
BIT[5] = BIT[5] + 2 = 5 + 2 = 7then next index to update is5 + (5 & -5) = 5 + 1 = 6BIT[6] = BIT[6] + 2 = 11 + 2 = 13then next index to update is6 + (6 & -6) = 6 + 2 = 8BIT[8] = BIT[8] + 2 = 36 + 2 = 38then next index to update is8 + (8 & -8) = 8 + 8 = 16which is out of range.
void update(int index, int val){ while(index <= n){ BIT[index] += val; index = index + (index & -index); } }
The time complexity of updating is O(logn).
Implementation
#include <bits/stdc++.h>
using namespace std;
void update(int index, int val, vector<int> &BIT)
{
int n = BIT.size();
while (index <= n)
{
BIT[index] += val;
index = index + (index & -index);
}
}
int query(int index, vector<int> &BIT)
{
int sum = 0;
while (index > 0)
{
sum += BIT[index];
index = index - (index & -index);
}
return sum;
}
int main()
{
cout << "Enter the size of array: ";
int n;
cin >> n;
vector<int> arr(n + 1, 0);
vector<int> BIT(n + 1, 0);
cout << "Enter the elements of array: ";
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
}
for (int i = 1; i <= n; i++)
{
update(i, arr[i], BIT);
}
cout << "Enter the number of queries: ";
int q;
cin >> q;
while (q--)
{
cout << "Enter the type of query (1 for update, 2 for query): ";
int type;
cin >> type;
if (type == 1)
{
cout << "Enter the index and value to update: ";
int index, val;
cin >> index >> val;
update(index, val, BIT);
}
else
{
cout << "Enter the left index : ";
int l, r;
cin >> l;
cout << "Enter the right index : ";
cin >> r;
cout << "Sum of elements from l " << l << " to " << r << " is: " << query(r, BIT) - query(l - 1, BIT) << endl;
}
}
}
Applications
Range Sum Queries: Fenwick Tree can be used to find the sum of elements from index
ltorin an array.Inversion Count: Fenwick Tree can be used to find the number of inversions in an array.
Last updated