三个重要函数:lowbit updata getsum
两个重要的数组: a[N]是原数据,c[N]则是建立的树状数组
c[i]存储的是从a[i]开始往前lowbit(i)个数据的和
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
二进制 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 |
lowbit | 1 | 2 | 1 | 4 | 1 | 2 | 1 | 8 |
下标 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
二进制 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 | 10000 |
lowbit | 1 | 2 | 1 | 4 | 1 | 2 | 1 | 16 |
现在来讲一下lowbit的作用:找到一个数的二进制最末位开始向前找到的第一个“1”的十进制值
int lowbit(int x)
{
return x&(-x);
}
(-x)在在电脑中是以补码的形式储存的
例如10的二进制是1010,-10的二进制是10的反码+1,即0101+1 = 0110,再把1010和0110按位与,即1010&0110 = 0010 = 2 。
update(int i,int x)函数则是往a[i]加上x,那么c[i]与c[i]之后的一些c数组的值都要发生改变,那么这个时候怎么对c数组进行操作呢?只要i+=lowbit(i)就行了。
void updata(int i,int x) //在i的位置加x
{
while(i<=n)
{
c[i]+=x;
i+=lowbit(i);
}
}
比如在a[10]上+x,10的二进制是1010,
lowbit(i)=0010,i=1010+0010=1100,
lowbit(i)=0100,i=1100+0100=10000,
……
所以i+=lowbit(i)的操作就是每次把最后一个"1"的位置再+1,这样可以推出这个i究竟属于哪些c数组管辖。
int getsum(int i) //求1~i的和
{
int res=0;
while(i>=1)
{
res+=c[i];
i-=lowbit(i);
}
return res;
}
getsum 的作用是求前缀和。13的二进制是1101,lowbit=0001=1
1101-0001=1100=12 lowbit=0100=4 c[12]=a[9]+a[10]+a[11]+a[12]
1100-0100=1000=8 lowbit=1000=8 c[8]=a[1]+……+a[8]
1000-1000=0000
这样应该懂了吧。