树状数组模板

时间复杂度:logn

树状数组的唯一作用:快速求前缀和并支持单点修改(增加一个数,或者加当前数相反数,再加自己想修改的数,实现数值替换)

区间修改,单点查询题-----需要将原题目差分

区间修改,区间查询。

树状数组公式(最好记忆)

C[x]=(x-lowbit(x),x] 区间内数的和

lowbit(x)=x & -x = 2^k 返回最后1的位置

x位置的父节点:x+lowbit(x)

操作

1.某位置加上一个数 ,从该节点向上一层层的父节点全加上这个数 o(logn)

2.求某一个前缀和 C[x]+C[x-lowbit(x)] ....递归调用 o(logn)

裸题模板:

https://www.acwing.com/problem/content/1266/

image-20220329190956593

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5+10;

int n,m;
int a[N],tr[N];


int lowbit(int x)
{
    return x & -x;
}

void update(int x,int v){
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;//x+lowbit(x)为父节点位置,一直到最高层每个结点都加上这个数。
}

int query(int x){
    int res=0;
   for(int i=x;i;i-=lowbit(i)) res+=tr[i]; //(x-lowbit(x),x] 区间内的和即为前缀和
   return res;
}


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%d", &a[i]);
    }
    
    //初始化
    
    for(int i=1;i<=n;i++){
        update(i,a[i]);
    }
    
    while (m -- ){
        int oper,a,b;
        scanf("%d%d%d",&oper,&a,&b);
        if(oper==0){
            cout<<query(b)-query(a-1)<<endl;
        }else{
            update(a,b);
        }
        
    }
    return 0;
}

posted @ 2022-03-29 19:09  秋月桐  阅读(21)  评论(0编辑  收藏  举报