引理1 下列函数lowbit
int lowbit(int x) { return x & (-x); }
能够返回数x的二进制最低位1对应的值。(例如,lowbit(10011010000)=10000。)
证明:设x的最低位的1在第k位(x=...1000...000)。则-x=~x+1=(...0111...111+1)=...1000...000。也就是说,~x在+1时,前(k-1)位一直进位,直到第k位时,由于~1=0,进位结束,且第k位仍为1。由于进位结束,则k位以上变为原来的反码。因此,x与-x仅有第k位一位相同。证毕。
定义1 树状数组第i个元素c[i]定义为
,其中
为从
往下枚举到
最后一个连续满足lowbit(j)<=lowbit(i)的j。
例如当i=6,lowbit(6)<=lowbit(6), lowbit(5)<=lowbit(6),而lowbit(4)>=lowbit(6),故k=5。尽管lowbit(1)<=lowbit(6),但不满足“连续”,故k≠1。
定理1
。
证明:根据树状数组的定义,c[k]为从k开始向下连续满足lowbit(i)<=lowbit(k)的a[i]的和。只需证对于c[k],这些元素的个数(设为p)为lowbit(k)。
① 先证lowbit(k-lowbit(k))>lowbit(k)。如果这个结论成立,那么p<=k-lowbit(k)。根据lowbit函数的定义,设k的二进制的最低位1在第u位,则k的第1~(u-1)位为0。那么,k-lowbit(k)的第u位为0。故k-lowbit(k)的第1~u位为0,lowbit(k-lowbit(k))>lowbit(k)。
② 再证, 定理1证毕。 由此我们可以写出如下的求和代码: 定理2 若给a[x]加一个数v,则下列函数update能够将c数组更新至正确的值。 证明:只需更新满足k-lowbit(k) ① 先证对于所有update函数中更新的c[k],都有k-lowbit(k) ② 下面证update函数没有遗漏任何一个满足k-lowbit(k) 定理2证毕。,
。仍设k的二进制的最低位1在第u位,设i=k-w,则当0<=w
int getsum(int x) // sum[1, 2, ..., x]
{
int ans = 0;
for(int i = x; i; i -= lowbit(i))
{
ans += c[i];
}
return ans;
}
三、树状数组的单点更新操作
void update(int x, int v)
{
for(int k = x; k <= n; k += lowbit(k))
{
c[k] += v;
}
}
,其中
为k的低(u-1)位,
是k的第u及以上的位,|为按位或运算。又设
,其中
是x的第u及以上的位,
。那么根据k>=x,必然有
。倘若lowbit(k)
,可知,当
时k-b