树状数组

本文介绍了一种高效的数据结构——树状数组,适用于频繁修改数组元素并查询区间元素之和的场景。通过具体实现代码展示了如何进行修改操作和求和操作,并解释了其背后的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一区间元素之和的时候,可以考虑使用树状数组


定义:a[1...N]为原数组,c[1...N]为对应的树状数组;


其中:用c[i]表示从数据数组a中某一处一直到a[i]共2^k个元素的总和 即a[i-2^k+1]~a[i] 

           2^K就是i的二进制表示中倒数第一个1以及之后的0(比如(1001000)2的2^k就是(1000)=8

低位(LowBit)

LowBit(x) = x&-x  

修改 (Modify)

如果我们修改了a[i],我们只需对c[i],c[i+lowbit(i)],c[i+lowbit(i)+lowbit(i+lowbit(i))]……进行修改,复杂度O(logn)

void modify(int i,int k)
{
      for(;i <= n;i += i&-i)c[i] += k;// 直接lowbit了
}
求和 (Sum)
原理:a[1]+...+a[i]=c[i]+c[i-lowbit(i)]+c[i-lowbit(i)-lowbit(i-lowbit(i))]……复杂度O(logn)

这种处理方式等效与每次将i二进制的1末尾删去一个1,那么就刚好跳出这个i管辖的区间而达到分段计值的目的

int Sum(int i)
{
     int ans = 0;
     for(;i;i -= i&-i)ans += c[i];
     return ans;
}

查询a[i]...a[j],则可调用sum(j)-sum(i-1)

实现代码:

#include <cstdio>
const int N = 500000;
int a[N],c[N],n,m;
void add(int i,int k)
{
    for(;i <= n;i += i&-i)c[i] += k;
}
int sum(int i)
{
    int ans = 0;
    for(;i;i -= i&-i)ans += c[i];
    return ans;
}
int main()
{
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i = 1;i <= n;i++)scanf("%d",a+i),add(i,a[i]);
    while(m--)
    {
        scanf("%d%d%d",&i,&j,&k);
        if(i)add(j,k-a[j]);
        else 
        {
            if(k == j){printf("%d",a[k]);continue;}
            printf("%d\n",sum(k) - sum(j-1));
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值