A tree-like array (Binary Indexed tree (BIT), Fenwick tree) is a data structure that queries and modifies the complexity of both log (n). It is primarily used to query the sum of all elements between any two bits, but only one element can be modified at a time, and a simple modification allows scope modification at the complexity of log (n), but only one element can be queried at this point.
The solution and program of tree array There are many online, here I want to think about the soul of this algorithm, that is, based on what kind of opportunity and inspiration to produce this wonderful idea. This is the direction I am interested in.
This algorithm is mainly used to query the sum of all the elements in an array of any two numbers, and this array we will often modify any number inside.
If we discard the operation of modifying the array, that is, the original array is immutable, and just doing the query, we can easily think of a method.
Set the original array a[n], we can construct another array c[n], take any subscript I, let c[i] = a[1] + a[2] + ... + a[i]
So if we're going to calculate the sum of the numbers between the subscript K and J (including K and j), sum = c[j]-c[k-1]
So as long as the array c[n] is built, the time complexity of the query operation is O (1) level, very fast
If the modification operation is added, the above method is not suitable, because if modified a[i], the corresponding c[i], c[i+1] 、......、 c[n], it should be modified. This modified time complexity is O (n) level, although the query operation is still O (1), but if the modification operation is many, this method is obviously not suitable.
If it is improved on this method, so that the time complexity of the modification operation is reduced, the query operation time complexity increases, the tree array of this algorithm to achieve this, so that the time complexity of the changes and queries are unified to O (log (n)), the advantage of log (n) is greater n, resulting in higher efficiency optimization
Let's look at the difference after the improvement
Originally:
C[1] = a[1]
C[2] = a[1] + a[2]
C[3] = a[1] + a[2] + a[3]
...
C[n] = a[1] + a[2] + a[3] + ... + a[n]
After improvement:
C[1] = a[1]
C[2] = a[1] + a[2]
C[3] = a[3]
C[4] = a[1] + a[2] + a[3] + a[4]
C[5] = a[5]
C[6] = a[5] + a[6]
C[7] = a[7]
C[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8]
...
C[n] = a[n–2^k + 1] + ... + a[n] "where K is the number of n binary end 0"
From the improved law, if we modify the a[i], we do not have to change all the elements after all C[i], but to select the changes. The time complexity of this modification is O (log (n)), which can be seen from the subscript formula of N–2^k + 1.
It's very intuitive to use a tree chart.
Query operation, in order to calculate the number of the first n and for example,
SUM (7) = C[7] + c[6] + c[4] = c[0x111] + c[0x110] + c[0x100]
SUM (Ten) = c[10] + c[8] = c[0x1010] + c[0x1000]
sum () = c[13] + c[12] + c[8] = c[0x1101] + c[0x1100] + c[0x1000]
See here Smart you should find some rules, with 7 binary 0x111 as an example, from right to left gradually remove 1, 0x110,0x100 that is 6 and 4, so get c[7] + c[6] + c[4]
In this way we can find the sum of the first n numbers, and then if we want to calculate the sum of the numbers between the subscript K and J (including K and j), sum = c[j]-c[k-1]
The procedure is as follows:
#include <stdio.h>//#include <windows.h>#include <string.h>#defineMAX 1000001intC[max];//This method allows you to calculate the number of the first 1 occurrences of a binary number from right to left.//Example://1 ———— 1//Ten ————//110100 ————//10111 ———— 1//10000 ———— 10000intLowbit (intt) {    returnt& (-t); //return n& (n^ (n-1));}//Modify a number in the array, Delta is incrementvoidModifyintNintDelta) {     while(N <=MAX) {        intD; C[n]+=Delta; N+=lowbit (n); }}//and the number of the first nintSumintN) {    intresult =0;  while(n! =0) {result+=C[n]; N-=lowbit (n); }    returnresult;}intMain () {intN =0, M =0, i =1; scanf ("%d%d", &n, &M); Memset (c,0,sizeof(c));  while(n--)    {        inttemp; scanf ("%d", &temp); Modify (I++, temp); }     while(m--)    {        Chars[Ten]; intI =0, A =0, num; scanf ("%s%d%d", &s, &i, &A); if(strcmp (s),"QUERY") ==0) {num= SUM (A)-SUM (-1); printf ("%d\n", num); }        Else if(strcmp (s),"ADD") ==0) {Modify (I, A); }    }    //System ("pause");}
Summary: In the absence of modification operation, we use c[n] to represent the sum (n) of the first n of the array A, and in the case of a modification, we still use the number in array C to represent SUM (n), and the difference is that there are multiple numbers such as c[i], c[j], c[k] ... And how to find I,j,k by n ... These correlation numbers and the construction of the group C, is the tree array of the key to the algorithm-the number of n is decomposed into 2 of the number of times, such as 2, 4, 8, 16.
 ACM tree-shaped array