一、关于树状数组
树状数组(Binary Indexed Tree(B.I.T), 二进制索引树)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。
二、核心思想
1、树状数组里的每个元素都是原数组里的一个或者多个连续元素的和;
2、在进行连续求和操作a【1】+a【2】+a【3】+…..+a【n】时,只需要将树状数组中的某几个元素进行求和;
3、在对某一个元素进行修改时,也只需要修改树状数组中的某几个元素的和即可。
三、树状数组的基本操作
ps:下面的c【】数组就是树状数组。
1、预操作
lowbit函数就是求出参数二进制中最后一个1的位置的十进制值。
int lowbit(int x)
{
x=x&-x;
return x;
}
2、修改区间和
这里有2种修改:向下更新和向上更新
void update(int num,int val)
{
while(num>0)
{
c[num]+=val;
num-=lowbit(num);//向下更新
}
}
void update(int num,int val)
{
while(num>0)
{
c[num]+=val;
num+=lowbit(num);//向上更新
}
}
3、查询区间和
同样地,也有2中查询方式,向上查询和向下查询。
int getSum(int num)
{
int sum=0;
while(num<=n)
{
sum+=c[num];
num+=lowbit(num);//向上查询
}
return sum;
}
int getSum(int num)
{
int sum=0;
while(num<=n)
{
sum+=c[num];
num-=lowbit(num);//向下查询
}
return sum;
}
三、扩展
以上都是对一维数状数组的基本操作,自然地,也存在二维的树状数组。
二维树状数组是在一维树状数组的基础上拓展而来的一个由数字构成的大矩阵,能进行两种操作对矩阵里的某个数加上一个整数(可正可负)或查询某个子矩阵里所有数字的和,要求对每次查询,输出结果。一维树状数组很容易扩展到二维,在二维情况下数组c[][]的树状数组定义为:
c[x][y] = ∑ a[i][j],
x-lowbit(x) + 1 <= i <= x,
y-lowbit(y) + 1 <= j <= y.
更新和查询操作:
void add(int x, int y, int z){ //将点(x, y)加上z
int tmp = y;
while(x <= n){
y = tmp;
while(y <= n)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
void ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
int res = 0, tmp = y;
while(x){
y = tmp;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
}