对于区间的单点处理:
#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;
}
京公网安备 11010502036488号