对于区间的单点处理:

#include<iostream> 
using namespace std;
const int N=1000010;
typedef long long ll;
ll a[N<<2],tree[N<<2];//首先对于数组我们要开正常数组的四倍之多

void build_tree(int node,int begin,int end){  //建树
    if(begin==end){
        tree[node]=a[begin];
        return;
    }
    int mid=(begin+end)>>1;
    int left_node=2*node+1;
    int right_node=2*node+2;
    build_tree(left_node,begin,mid);
    build_tree(right_node,mid+1,end);
    tree[node]=tree[left_node]+tree[right_node];  //pushup父结点的情况
}

void update_tree(int node,int begin,int end,ll index,ll val){  //更新树上各点的数值
    if(begin==end){  //边界条件时进行更新
        a[index]=val;
        tree[node]=val;
        return;
    }
    int mid=(begin+end)>>1;
    int left_node=2*node+1;
    int right_node=2*node+2;
//判断该进行左递归还是右递归
    if(index<=mid&&index>=begin){ 
        update_tree(left_node,begin,mid,index,val);
    }
    else  update_tree(right_node,mid+1,end,index,val);
    tree[node]=tree[left_node]+tree[right_node];
}

ll query_tree(int node,int begin,int end,int L,int R){
//递归出口一般来说有三个,如果查询区间不在当前的范围内,那么就返回0
//查询区间如果完全包含在当前的区间范围内,那么就不需进行向下递归
//如果当前的区间长度为1时,也可以作为出口
    if(L>end||R<begin)   return 0;
    else if(begin==end)  return tree[node];
    else if(L<=begin&&R>=end)  return tree[node];
    int mid=(begin+end)>>1;
    int left_node=2*node+1;
    int right_node=2*node+2;
    ll left_sum=query_tree(left_node,begin,mid,L,R);
    ll right_sum=query_tree(right_node,mid+1,end,L,R);
    return left_sum+right_sum;
}

int main(){
    int n,q;
    cin>>n>>q;
//这里要注意,我们的下标是从0开始的
    for(int i=0;i<n;i++)  cin>>a[i];
    build_tree(0,0,n-1);
    while(q--){
        int t;
        cin>>t;
        if(t==1){
            ll i,x;
            cin>>i>>x;
            x+=a[i-1];
            update_tree(0,0,n-1,i-1,x);
        }
        else if(t==2){
            ll l,r;
            cin>>l>>r;
            ll ans=query_tree(0,0,n-1,l-1,r-1);
            cout<<ans<<endl;
        }
    }
    return 0;
}

区间修改的模板:

#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1000010;
ll n,m,a[maxn],tag[maxn<<2],ans[maxn<<2];
//tag数组是用来作为懒标记的
inline ll ls(ll p){
    return p<<1;
}
inline ll rs(ll p){
    return p<<1|1;
}
inline void push_up(ll p){
    ans[p]=ans[ls(p)]+ans[rs(p)];
}
//pushup目的是为了维护父子结点的逻辑关系
void build(ll p,ll l,ll r){
    tag[p]=0;  //这是初始的懒标记设为0
    if(l==r){
        ans[p]=a[l];
        return;
    }
    ll mid=(l+r)>>1;
    build(ls(p),l,mid);
    build(rs(p),mid+1,r);
    push_up(p);
}
inline void f(ll p,ll l,ll r,ll k){
    tag[p]=tag[p]+k;
    ans[p]+=k*(r-l+1);
}
//向下递归更新懒标记
inline void push_down(ll p,ll l,ll r){
    ll mid=(l+r)>>1;
    f(ls(p),l,mid,tag[p]);
    f(rs(p),mid+1,r,tag[p]);
    tag[p]=0;
}
inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k){
    //nl,nr为要修改的区间,l,r,p为当前的区间端点和当前的结点编号 
    if(nl<=l&&r<=nr){
        ans[p]+=k*(r-l+1);
        tag[p]+=k;
        return;
    }
    push_down(p,l,r);
    //回溯pushup之前是 向下传递的,自然要每个结点都更新到 
    ll mid=(l+r)>>1;
    if(nl<=mid)  update(nl,nr,l,mid,ls(p),k);
    if(nr>mid)   update(nl,nr,mid+1,r,rs(p),k);
    push_up(p);//向上进行回溯更新父结点
}
inline ll query(ll q_x,ll q_y,ll l,ll r,ll p){
//q_x,q_y为要查询区间的端点
    ll res=0;
    if(q_x<=l&&r<=q_y)  return ans[p];
    ll mid=(l+r)>>1;
    push_down(p,l,r);
    if(q_x<=mid)  res+=query(q_x,q_y,l,mid,ls(p));
    if(q_y>mid)   res+=query(q_x,q_y,mid+1,r,rs(p));
    return res;
}
int main(){
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=n;i++)  cin>>a[i];
    build(1,1,n);
    while(m--){
        int t;
        cin>>t; 
        if(t==1){
            ll i,x;
            cin>>i>>x;
            update(i,i,1,n,1,x);
        }
        else{
            ll x,y;
            cin>>x>>y;
            ll ans=query(x,y,1,n,1);
            cout<<ans<<endl;
        }
    }
    return 0;
}