树状数组
时间复杂度为O(lgn)
一般讲到树状数组都会少不了下面这个图:
据图可知: c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。
分析上面的几组式子可知,当 i为奇数时,ci=ai;当 i为偶数时,就要看 i的因子中最多有二的多少次幂,例如,6的因子中有 2的一次幂,等于 2,所以 c6=a5+a6(由六向前数两个数的和),4的因子中有 2的两次幂,等于 4,所以 c4=a1+a2+a3+a4(由四向前数四个数的和)。
-
有公式:cn=a(n-a^k+1)+.........+an(其中k 为 n的二进制表示中从右往左数的 0的个数)。
求 a^k:
int lowbit(int x){ return x&(-x); }
-
求数组的和的算法如下:
-
首先,令sum=0,转向第二步;
-
接下来判断,如果 n>0的话,就令sum=sum+cn转向第三步,否则的话,终止算法,返回sum 的值;
-
n=n –lowbit(n)(将n的二进制表示的最后一个零删掉),回第二步。
代码实现:
int sum(int n){ int sum = 0; while (n) { sum += c[n]; n -= lowbit(n); } return sum; }
-
当数组中的元素有变更时,树状数组就发挥它的优势了,算法如下(修改为给某个节点i 加上x ):
-
当 i<=n时,执行下一步;否则的话,算法结束;
-
ci=ci+x,i=i+lowbit(i)(在i 的二进制表示的最后加零),返回第一步。
代码实现:
void change(int i, int x){ while (i <= MAX) { c[i] += x; i = i + lowbit(i); } }