一、插点问线,如“士兵杀敌(二)”要向上修改,向下统计;一般是修改某个位置上的值,查找的是一段区间的和;
二、插线问点,如“士兵杀敌(四)”要向上统计,向下修改;一般是修改一段区间的值,查找的是某个位上的值;
下图中的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;
}