(一)定义:树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主 要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。
(三)实战场:插点问线 —— 南阳理工116
插线问点 —— 南阳理工123
(四)插点问线:
问题描述——假设有数组a[0..n](0 <= n <= 1000000 ),我们多次需要求特定连续区间的和a[x] + a[x+1] + ····a[y] (0 =< x<=y<=n), 测试样例组数(1<=m<=1000000),数组元素小于100。
解放方案(一) :从x 到 y 依次进行遍历,时间复杂度( O(n) );
解决方案(二) :利用树状数组进行查询求和操作,时间复杂度( O(log(n) )
详解示意图:
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]
故a[x] + a[x+1] +···a[y] = c[y] - c[x-1] ;
int Judge (int x) {
return (x&(x^(x-1)));
}
int Judge (int x) {
retrun (x*(-x));
}
当想要查询一个SUM(n)(求a[n]的和),可以依据如下算法即可:
详见代码:
int Sum(int x){
int sum = 0;
while(x > 0){
sum = sum + c[x];
x = x - Judge(x);
}
return sum;
}
解放方案(一) :从x 到 y 依次进行遍历,时间复杂度( O(n) );
解决方案(二) :利用树状数组进行查询求和操作,时间复杂度( O(log(n) )
c[1] = a[1]
c[2] = a[2]
c[3] = c[2] + a[3]
c[4] = a[4]
c[5] = c[4] + a[5]
c[6] = c[4] + c[6]
c[7] = c[4] + c[7]
c[8] = a[8]
详细代码:
void build(int x,int y,int z,int length) {
while(x<=length) {
tree[x]+=z;
x+=Judge(x);
}
//对从 X 开始的节点进行增加操作,仅需对X后的同层最小节点增加或删减
y+=1;
while(y<=length) {
tree[y] -= w;
y+=Judge(y);
}
//对 Y + 1 后修改元素删减,因为合理修改区间是[X-Y],而之前操作进行了集体增加,\n
//所以还应对不应该增加或减少的元素还原
}
//如 : 区间2-6 增加 10 ,使得 c[2] +10 && c[4] + 10; 如查询tree[3] = tree[3] + c[2];