树状数组

 一、插点问线,如“士兵杀敌(二)”要向上修改,向下统计;一般是修改某个位置上的值,查找的是一段区间的和;
二、插线问点,如“士兵杀敌(四)”要向上统计,向下修改;一般是修改一段区间的值,查找的是某个位上的值;

下图中的C数组就是树状数组,a数组是原数组

 
 
 
 
 
 
可以发现这些规律
C1=a1
C2=a1+a2
C3=a3
C4=a1+a2+a3+a4
C5=a5
……
C8=a1+a2+a3+a4+a5+a6+a7+a8
……
C2^n=a1+a2+….+a2^n
 
 
对于序列a,一个(树状)数组C定义C[i] = a[i – 2^k + 1] + … + a[i],k为i在二进制下末尾0的个数。
以上可以看出:设节点编号为i,那么这个节点管辖的区间为2^k
 
算这个2^k有一个快捷的办法,
定义一个函数如下即可:
int lowbit(int x)
{
return x & (x ^ (x – 1));
//等价于return x & (-x);
}
 
修改算法:例如(给某个结点i加上x):   
step1: 当i > n时,算法结束,否则转第二步;  
step2: Ci = Ci + x, i = i + lowbit(i)转第一步。  
 i = i +lowbit(i)这个过程实际上也只是一个把末尾1补为0的过程。   对于数组求和来说树状数组简直太快了! 
 具体函数如下:
void update(int i , int x)
{  
 while(i <= n)  
 {
  C[i] += x;
  i += Lowbit(i);  
 }   
}
 
 
若要求数组a的1~n项和,
可以依据如下求和算法即可:
 step1: 令sum = 0,转第二步;
 
step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;
  
step3: 令n = n – lowbit(n),转第二步。
  
具体求和函数如下:
int Sum(int n)
{ int sum = 0;   
        while (n> 0)  
 {   sum += C[n];  
                  n -= Lowbit(n);  
 }  
 return sum;  
}
 
 
 
原文地址:https://www.cnblogs.com/xiaofanke/p/3102505.html