树状数组模板
时间复杂度: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/
#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;
}