树状数组(单点修改,区间查询)

已知一个数列,你需要进行下面两种操作:

        将某一个数加上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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值