对于区间信息进行快速查询是设计许多程序需要实现的功能,树状数组是属于其中比较简单的一种数据结构,其主要功能有查询前缀和与更新数据。
对于树状的东西,一般又离不开2和二进制,这里我们需要引入一个lowbit的概念。对于每个数组编号,我们可以求出其最低有效位的大小,数学上,数组编号的中心将会成为根(它的lowbit最高)。通过lowbit我们把相对对称的位置取到了同一高度(这里的数学证明暂且不管)。这棵树具有的性质是左节点加上自己的lowbit是父节点编号,而右节点则是减去。下面是求lowbit的代码:
int lowbit(int x)
{
int result=1;
while(!(1&x))
{
x>>=1;
result<<=1;
}
return result;
}
下面就要说说add操作了,我们如果对某个原始数据加上了d,那么所有包含该数据的区间就都应该加上d。如何操作呢?我们用一个C数组来储存这样一个信息:C[x]表示以x结尾,长度为lowbit(x)区间上的和。这样我们可以发现,每次更新位置为x的原始数据,在lowbit(x)之下的值都不用更新了。也就是从x往上更新就可以了,注意不要超过最大范围:
void add(int x,int d)
{
while(x<=MAX)
{
c[x]+=d;
x+=lowbit(x);
}
}
查询也并不难,只要把x之前所有和加起来就行了,方法是沿着儿子一步步向下走:
int query(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
至此,树状数组的基本功能就全部实现了。