树状数组简单笔记

(简要笔记,仅供参考,可能存在瑕疵或者不正确的地方,望指正)

1用于求一组数组的前缀和,更新其中某个下标的数。

2操作

(1)单点更新(2)区间更新(3)区间查询

3组成

int c[N]//树状数组。

单点更新

int lowbit(int x)//得到二进制形式中最后的1所在的位置,用于进行块的跳转。
{
return x&(-x);
}
void add(int x,int v)//用于单点修改,x为修改的下标,v是该下标增加的值
{
for(;x<=n;x+=lowbit(x))
c[x]+=v;
}

区间查询

int getsum(int x)//求[1,x]的区间和
{
int ans;
        for(;x;x-=lowbit(x))
ans+=c[x];
return ans;
}
int query(int l,int r)//求[l,r]的区间和。
{
return getsum(r)-getsum(l-1);//用[1,r]的和减去[1,r-1]
}

区间修改//更新一个区间的数字

(1)差分数组b[2][i]=a[i]-a[i-1]//b[0][i]记录下标为i的数和i-1的差,可以将更新一个区间变成

更新差分数组两个下标的数字。b[0][l]+=v,b[0][r+1]-=v。

b[1][i]=i*b[0][i]//用于维护b[x]*x。

(2)a[i]=b[i]+b[i-1]...b[1]。

(3)c[x]=(x+1)*(b[1]+b[2]+...b[x])-(b[x]*x+b[x-1]*(x-1)...+b[1]*1)。

void add(int x,int v)
{
        int v1=x*v;
        for(;x<=n;x+=lowbit(x))
        {
        b[0][x]+=v;
        b[1][x]+=v1;
        }
}
void Add(int l,r,v)//让[l,r]区间的数都加v
{
add(l,v);
add(r+1,-v);
}

在int main 中输入原本数组a[i]时

if(i==1)
add(i,a[i]);
else
add(i,a[i]-a[i-1]);

用差分数组的查询

单点查询

int getsum1(int x)//求a[i]的值
{
int ans;
for(;x;x-=lowbit(x))
ans+=b[0][x];
return ans;
}

区间查询

int getsum2(int x)//求[1,x]的区间和
{
int ans0=0;
int ans1=0;
int x1=x;
for(;x;x-=lowbit(x))
{
ans0+=b[0][i];
ans1+=b[1][i];
}
return ans0*(x1+1)-ans1;
}
int query(int l,int r)//求区间[l,r]的和
{
return getsum2(r)-getsum2(l-1);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值