已知一个数列,你需要进行下面两种操作:
将某一个数加上x(单点修改)
求某区间每个数的和(区间求和)
图示如下:
这里定义一个lowbit函数,用来表示非负整数n在二进制下的最低为1及其后面的0构成的数,例如:lowbit(2)=lowbit(0010)=2
可以发现,t[x]的父节点为t[x+lowbit(x)],例如:t[4] = t[2+lowbit(2)]
int lowbit(int x)
{
return x&(-x);
}
单点修改
对某一个点进行修改,如a[1]+k,则他的祖先节点t[1],t[2],t[4],t[8]都需要加k
void add_dandian(int x,int k)
{
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=k;
}
区间查询
先来计算区间[1,x]的和:
有图可看出,sum[7] = t[7] + t[6] + t[4] ,其中,6 = 7 - lowbit(7) , 4 = 6 - lowbit(6),所以我们可以通过不断的-lowbit操作来实现求和
所以在求区间[l,r]的和时,可以用 [l,r] = [1,r] - [1,l-1] 来计算
ll search(int l,int r)
{
ll ans=0;
//求区间[1,l-1]的和
for(int i=l-1;i;i-=lowbit(i))
ans-=t[i];
//求区间[1,r]的和
for(int i=r;i;i-=lowbit(i))
ans+=t[i];
return ans;
}