I read 2 - 3 tutorials of binary indexed tree(AKA Fenwick tree) on internet, but I didn't understand what it actually does and what is the idea behind BIT.
The tutorial that I read is
Please help me to make me understand about BIT.
I read 2 - 3 tutorials of binary indexed tree(AKA Fenwick tree) on internet, but I didn't understand what it actually does and what is the idea behind BIT.
The tutorial that I read is
Please help me to make me understand about BIT.
The top coder article is not so clear. Here is the big idea that may get you started.
BITs are good for storing dense maps from integers to integers f[i], where i >= 1 and you are interested in retrieving sums over ranges of the map domain, i.e. sum_{i = a..b} f[i] for arbitrary a and b. If you were coding in C this would be:
sum = 0; for (i = a; i <= b; i++) sum += f[i];
By dense I mean f[i]>0 for most i. If you have a sparse map, other data structures are better.
BITs let you speed up this computation so that the run time of the sum - rather than being proportional to b - a - is instead proportional to log(b+a). Time to insert a new element is similar.
To do this, the BIT stores a different map g[k] rather than f[i]. The contents of g are defined in a clever way.
g[k] = sum_{i = k - d + 1 .. k} f[i]
where d is the value of k with all but the lowest order bit set to zero. For example, if k=8, then d=8. If k=14, then d=2, etc.
Note there is no explicit tree. The tree is logical as shown in the tutorial pictures. The only storage is the array g.
Why is this a good idea? It turns out that to find sum_{i = a..b} f[i], you need only sum up at most 2 ceiling(log(b+a)) elements of g. These elements can be determined by analyzing the binary 1 bits of a and b. The details are shown in the tutorials.
The simplest example: if you want sum_{i = 1..p} f[i], then construct the series of indices p_1, p_2, ... p_n where p_1 = p and p_(i+i) is formed by removing the lowest order 1 bit from p_i. Therefore n is one less than the number of 1's in the binary representation of p. Now just compute
sum_{k = p_1, p_2 ... p_n} g[k]
If you experiment and think about this a bit (pun intended) you'll see why it works.
Binary indexed tree also known as Fenwick tree, i think binary indexed tree is less known as compared to Fenwick tree, so when we find for binary indexed tree we find less material, but this is just my feeling!
In simple words, Fenwick tree (aka Binary indexed tree) is a data structure that maintains a sequence of elements, and is able to compute cumulative sum of any range of consecutive elements in O(logn) time. Changing value of any single element needs O(logn) time as well. The structure is space-efficient in the sense that it needs the same amount of storage as just a simple array of n elements.
A practical example to illustrate above can be found at various places over net, i.e.
http://codeforces.com/blog/entry/619
http://michaelnielsen.org/polymath1/index.php?title=Updating_partial_sums_with_Fenwick_tree
And there are lot more example over net...
A binary index tree is a data structure allowing retrieval of a value by its prefix. My understanding of binary index trees is that they are more or less analogous to tries. For example, lets say you have three numbers 1323, 1697 and 1642. You could store the numbers in a tree:
1-3-2-3
-6-9-7
-4-2
where each node represents a 10s place. Now you can look up any number like you can look up a name in a telephone directory, letter by letter. Here, each node is by 10s, but you can choose a different base to make the representation as compact as possible. For example, you might use base 8 in which case each node stores 4 bits.
This data structure allows you to add numbers easily. For example, lets say you want to add numbers #1 (1323) and #3 (1642). Then you start at the leaf representing each number and work upward, multiplying by a power of the radix (here 10) as you go: 3+2, then (2+4)*10, then (6+3)*100, then (1+1)*1000.
BIT is a very fancy thing, the key to understand it is knowing how quick-segment algorithms work.
The very basic idea of a quick-segment algorithm & data structure is to 'skip' something.Think about a array a[1..n] of integers.Now you want yet another array C[1..n],in C[i] contains the sum of C[i],C[i-1] to C[k(i)](k is some sort of magic function (O-O) ).
When you want to get the sum of a[1..i], you can write:
int get_sum(int i) {
if (i == 0)
return 0;
return get_sum(k(i)-1)+C[i];
}
It is quite simple to understand yeh? We just use C[i] = sum(a[k(i)..i]) instead of going though the whole segment.And when we want to change some element, we use a array called 'add(pos, i)' means add i in a[pos]:
(k'(x) is a function returns the smallest y >= x that k(y) <= x)
void add(int pos, int i) {
if (pos <= n) {
C[pos] += i;
add(k'(pos), i);
}
}
The core of the code is also 'skip'.It is clear that C[k'(pos)] is the smallest element whose 'control segment(C[k(i)..i])' contains C[pos].We only update the elements that is bound up with C[pos] instead of dealing with all of the elements.
Now the question changed into : 'Finding out a suitable k(x) & k'(x) to finish the code'. k(x) = x-sqrt(n) is a simple function,with it the operation above is O(sqrt(n)). Well a better choice is the function BIT(i).
BIT(i) is to count the first '1' in the binary of i, something like:
(110100)2 --BIT--> (100)2
(111)2 --BIT--> (1)2
(100000)2 --BIT--> (100000)2
A quick way to calculate BIT is using binary operators:
BIT(x) = x & ((~x) + 1)
Let us suppose x = (101100)2, ~x = (010011)2, (~x)+1 = (010100)2, x & ((~x) + 1) = (000100)2. It really work! (~x)+1 makes all of the bits except BIT(x) be opposite, and the '&' clear the useless bits.
Because of -x = (~x)+1 (See how negative integers is turned into binary) BIT(x) = x & (-x)
Now we get a powerful function. I give the method without explaining(It's better for you to understand them by yourself):
k(i) = i-BIT(i)+1
k'(i) = i+BIT(i)
Try to use the k & k' to see the code above.
[Graph][https://i.sstatic.net/j5z5e.png]
Graph is from the Internet