您的位置:首页 > 其它

树状数组小结

2015-09-06 18:04 239 查看

树状数组基本概念

树状数组也是进行区间操作的常用数据结构。树状数组适用于单个元素经常修改,而且还反复求部分的区间和的情况.

对于数组a,构造一个新的数组C,使得C[i] = a[i-2^k+1] + a[i-2^k+2] + ... + a[i];
(1) i >= 1;
(2) k为i在二进制表示下末尾的连续的0的个数,2^k = i&(-i),通常用lowbit(i)表示i对应的2^k,lowbit(i) = 2^k = i&(-i);
则数组C为数组a的树状数组。

数组数组的结构

树状数组对应的结构如下图所示:



C[i] = a[i-lowbit(i)+1] + ... + a[i]
C[1] = a[1]
C[2] = a[1] + a[2]
C[3] = a[3]
C[4] = a[1] +a[2] + a[3] + a[4]

树状数组的操作

[b]一、求连续区间的和[/b]
树状数组可以快速的求数组a的一个连续区间的和:
sum[k] = a[1] + a[2] + ... + a[k],则a[i] + a[i+1] + a[i+2] + ... +a[j] = sum[j] - sum[i-1]
如果用C数组来表示即为:
sum[k] = a[1] + a[2] + .. a[k] = C[N1] + C[N2] + ... +C[Nm]
其中 Nm = k, Ni-1 = Ni - lowbit(Ni), N1 >=1


//查询
int Query(int p, int n){
int sum = 0;
while (p >= 1){
sum += gC[p];
p -= gLowBit[p];
}
return sum;
}


其中有log(n)个C元素,这就使得树状数组在连续区间求和时,可以达到log(n)的效率。
证明略

[b]二、单点更新[/b]
对原始数组a中的一个元素ai进行更新,树状有且仅有如下几项会被更新:C[N1], C[N2], ... C[Nm]
其中,N1 = i, Nk+1 = Nk + lowbit(Nk),且Nm <= N


//更新
void Update(int p, int n, bool add){
while (p <= n){
if (add){
gC[p] ++;
}
else{
gC[p] --;
}
p += gLowBit[p];
}
}


树状数组和线段树

树状数组的应用范围窄,树状数组适用于单个元素经常修改,而且还反复求部分的区间和的情况。所有能用树状数组解决的问题,均可以用线段树解决;
树状数组和线段树的时间复杂度均为O(nlogn),但是树状数组的常数小,效率略高;且树状数组的编程复杂度低。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: