#include <iostream>
using namespace std;
typedef unsigned long long ll;
const int maxn=1e5+5;
int a[maxn];
struct node
{
int l,r;
ll sum;
}e[maxn<<2];
void build(int l,int r,int index)///左端点l,右端点r,节点序号index
{
e[index]={l,r,0};///赋值左右端点
if(l==r) {e[index].sum=a[l]; return;}///递归到根节点了,赋值,回溯
else///二分递归建树
{
int mid=(l+r)/2;///中点mid
build(l,mid,index*2);///建左子树,区间(l,mid),左子树节点的序号为index*2
build(mid+1,r,index*2+1);///建右子树,区间(mid+1,r),右子树节点的序号为index*2+1
e[index].sum=e[index*2].sum+e[index*2+1].sum;///维护区间和,等于左右区间的和
}
}
void updata(int num,int value,int index)
{
int l=e[index].l,r=e[index].r;///获取左右端点
if(l==num&&r==num) {e[index].sum+=value; return;}///更新值(注意更新方式,看是+还是直接改变),并且要记得返回
else ///递归更新树
{
int mid=(l+r)/2;
if(num>mid) updata(num,value,index*2+1);///目标在右子树中
else if(num<=mid) updata(num,value,index*2); ///目标在左子树中
e[index].sum=e[index*2].sum+e[index*2+1].sum;///回溯,更新区间
}
}
ll query(int l,int r,int index)
{
int L=e[index].l,R=e[index].r;
if(l<=L&&r>=R) return e[index].sum;///树上的该区间(L,R)完全包含在目标区间内,返回
else
{
int mid=(L+R)/2;
if(mid<l) query(l,r,index*2+1);///目标区间完全在右区间
else if(mid>=r) query(l,r,index*2);///目标区间完全在左区间,记得带等号
else///目标区间左右区间都有
{
return query(l,r,index*2)+query(l,r,index*2+1);
}
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);///区间(1,n),序号从第1个开始建起
//for(int i=1;i<=n;i++) cout<<e[i].sum<<endl;
for(int i=1;i<=m;i++)
{
int q,c,d;
scanf("%d%d%d",&q,&c,&d);
if(q==1) updata(c,d,1);
else {cout<<query(c,d,1)<<endl;}
}
}
/*
4 2
7 6 3 5
1 1 4
2 1 2
ans=17
*/
线段树模板
最新推荐文章于 2024-03-24 19:47:35 发布