Fenwick Tree? A Beautiful Data Structure!!!

Sagar Sharma
3 min readMay 5, 2020

--

More I look towards the logic behind this data structure more I get intrigued by it and then come to its implementation which sets the level of its own.

This is just an introductory explanation of the Fenwick tree with a simple example.

Introduction

Fenwick tree or Binary Indexed Tree is a data structure that can efficiently calculate prefix sums and update elements.

Basic idea

Each integer can be represented as a sum of powers of two. In the same way cumulative sum can be calculated as the sum of sets of this cumulative frequency.

Let the sum of sets of this cumulative frequency be represented by the array denoted by T.

T[4]=A[1]+A[2]+A[3]+A[4]

If you want to calculate the cumulative sum of A[1] to A[7] then

Cumulative Sum=T[7]+T[6]+T[4]{ T[7]=A[7], T[6]=A[6]+A[5], T[4]=A[1]+A[2]+A[3]+A[4]}

From where we get that T[7], T[6], and T[4] will contribute to prefix sum till 7?

7 is represented by 111 in binary. If you unset the last set bit then we get 110 which gives 6. Again if you unset the last set bit we get 100 which gives 4. So these are the indexes that contribute to prefix sum till 7.

How do we isolate the last set bit?

If “AND” the number with its two complements we get the last set bit of the number which we can subtract from the original number to unset the last set bit of the number. As shown in the image above 7 converted into 6 after unsetting the last set bit.

x-=(x&-x); //For unsetting the last bit which x goes to 0

Now the question comes where each number in the original array contributes in the array T.

Update

A[1] contributes to T[1],T[2],T[4],T[8] and so on{In binary 1->1,10,100,1000}

A[3] contributes to T[3],T[4],T[8] and so on{In binary 3->11,100,1000}

A[5] contributes to T[5],T[6],T[8] and so on{In binary 5->101,110,1000}

Here if we look closely then we can see we need to add last set bit to the number to go to the place where it will contribute next.

x+=(x&-x); //For adding the last set bit until x goes to the maximum length of the tree or original array.

Time Complexity

Space Complexity: O(N) for declaring another array of size N

Time Complexity:

O(log N) for each operation(update and query as well)

O(log N) for building the tree(n times updating the tree)

Example

Let's write some code for the range sum query using a Fenwick tree.

Updating the prefix sum tree

void update(int ind,int num){
while(ind<v.size()){
v[ind]+=num;
ind+=(ind & -ind); //Adding the last set bit
}
}

Querying on the prefix sum tree

int getsum(int ind){    int sum=0;
while(ind>0){
sum+=v[ind];
ind-=(ind & -ind); //Unset the last set bit
}
return sum;
}

Building the tree

for(int i=0;i<n;i++){
int num;
cin>>num;
update(i+1,num);
}

Getting Sum of range

while(t--){
int l,r;
cin>>l>>r;
cout<<getsum(r)-getsum(l-1)<<endl;
}

Wrap up

The binary indexed tree is easy to implement and takes the linear amount of memory space. The query and update operation takes O(logN) time

Practice Problems

For practicing more problems on this amazing data structure.

References

  1. https://cp-algorithms.com/data_structures/fenwick.html
  2. https://www.hackerearth.com/practice/notes/binary-indexed-tree-or-fenwick-tree/
  3. https://www.topcoder.com/community/competitive-programming/tutorials/binary-indexed-trees/

--

--