树状数组
| |对i的操作 | 循环条件 |
|–|–|–|–|
|区间查询,单点查询(求和c[7]+c[6]+c[4])|i-=i&-i | i>0|–|
|区间修改,单点更新(影响c[5]->c[6]->c[8])|i+=i&-i|i<=n|–|
一.树状数组结构
二.lowbit()函数
lowbit()函数
int lowbit(int x)//树状数组C[]包含A[]的个数
{
return x&-x;
}
三.区间查询(求和)+单点更新(构造C[])
A1.区间查询(求和)
int sum(int i)//第一步//[1,i]的和
{
int ret=0;
while(i>0){
ret+=c[i];
i-=lowbit();
}
return ret;
}
sum(r)-sum(l-1);//第二步//[l,r]的和
A2.单点更新(构造树状数组C[])
void update(int i,int val)//表面对A[]操作,实际对C[]操作
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
四.区间修改+单点查询
A1.区间修改
void add(int p,int x)//更改差分数组d[],即操作c[]
{
while(p<=n)
c[p]+=x,p+=p&-p;
}
void range_add(int l,int r,int x)//区间修改
{
add(l,x),add(r+1,-x);
}
A2.单点查询
int ask(int p)//因为差分,所以前缀和
{
int res=0;
while(p)
res+=c[p],p-=p&-p;
return res;
}
五.区间修改+区间查询
A1.区间修改
void add(int p,int x)//维护两个树状数组
{
for(int i=p;i<=n;i+=i&-i)
c1[i]+=x,c2[i]+=x*p;
}
void range_add(int l,int r ,int x)//修改区间
{
add(l,x),add(r+1,-x);
}
A2.区间查询
int ask(int p)//[1,p]的和
{
int res=0;
for(int i=p;i;i-=i&-i)
res+=(p+1)*c1[i]-c[2];
return res;
}
int range_ask(int l,int r)//[l,r]的和
{
return ask(r)-ask(l-1);
}