二叉索引树(树状数组)
树状数组的学习是看的这篇博文,从树状数组的作用, 原理和实现来讲解。仔细看看会有收获,下面是我自己的对树状数组的体会。
1.树状数组的应用。
当我们求解一个动态连续和查询问题的时候,树状数组就派上了用场, 它是一种数据结构,进行连续和查询时的时间复杂度为O(logn)。
从上图中我们可以发现一个规律,由a数组和c数组组成,
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];
相信大家也都看出规律来了,要根据i的奇偶分两种情况。
当i为奇数时,c[i]=a[i];
当i为偶数时,要看i的因子中最多有2的多少次幂,例如4=2^2,6的因子为2=2^1,8=2^3;所有4,6,8分别由4,2,8个a数组元素组成。且都是由i向前数相应的数。例如c[6]=a[5]+a[6];
(一)公式
ci=a(i-a^k+1)+………+an(其中 k 为 n 的二进制表示中从右往左数的 0 的个数,数到1就停止,当为奇数的时候低位总是1,所以k=0)。偶数可以自己动手算一下。
于是就有了树状数组的一个重要的因素。
int lowbit(int x)
{
return x&(-x);
}
在这里解释下该算法的含义,(来自白书)我们知道在计算机中,整数都是以其补码的形式表示的,因此-x实际上是x按位取反再加1的效果,
38288=1001010110010000
-38288=0110101001110000
与运算之后,前面的全变成0,之后的lowbit位不变,返回2^k;
求和
注意n-lowbit(n)的含义
int Sum(int n)
{
int sum=0;
while(n>0)
{
sum+=c[n];
n=n-lowbit(n);
}
return sum;
}
动态修改
void change(int i,int x)
{
while(i<=n)
{
c[i]=c[i]+x;
i=i+lowbit(i);
}
}