嗨嗨嗨大家好,水一篇题解大家觉得怎么样,我们就来讲一下这题模版,不想说什么,直接上代码吧
#include<bits/stdc++.h>
#define ll long long
#define lson l,mid,x<<1
#define rson mid+1,r,(x<<1)+1
using namespace std;
const ll N=1e6+9;
ll sum[N<<2],lazy[N<<2];
ll a[N],n,q;
inline void pushup(ll x){
sum[x]=sum[x<<1]+sum[(x<<1)+1];//向上回溯累加,一个节点加上他儿子节点的和
}
inline void pushdown(ll x,ll ln,ll rn){//ln,rn分别为左、右儿子区间含的数的个数
if (lazy[x]){//此处有lazy标记
lazy[x<<1]+=lazy[x];//他的左儿子继承lazy标记
lazy[(x<<1)+1]+=lazy[x];//他的右儿子继承lazy标记
sum[x<<1]+=lazy[x]*ln;//左儿子修改操作(+=此处lazy标记所存的数*左儿子区间含的数的个数)
sum[(x<<1)+1]+=lazy[x]*rn;//与左儿子同理
lazy[x]=0;//以下放完毕,清空
}
}
void build(ll l,ll r,ll x){//x为节点编号,l、r为区间开头和结尾
if(l==r){
sum[x]=a[l];//赋初值
return;
}
// #define lson l,mid,x<<1
// #define rson mid+1,r,x<<1+1
ll mid=(l+r)/2;//分成两端区间
build(lson);//lson,rson,分别为左儿子右儿子节点定义见上
build(rson);
pushup(x);
}
ll qs(ll L,ll R,ll l,ll r,ll x){//求[L,R]区间和
if (L<=l&&r<=R){//被完全包含的情况,直接回溯加回去
return sum[x];
}
ll mid=(l+r)>>1;//与建树同理,分为两个小区间
//左区间[l,mid] 右区间[mid+1,r]
// #define lson l,mid,x<<1
// #define rson mid+1,r,x<<1+1
pushdown(x,mid-l+1,r-mid);
ll res=0;
if (L<=mid){//要求的区间在左节点上
res+=qs(L,R,lson);
}
if (R>mid){//要求的区间在右节点上
res+=qs(L,R,rson);
}
pushup(x);
return res;//回溯相加
}
void qxg(ll L,ll R,ll va,ll l,ll r,ll x){//将[l~r]+=va
if (L<=l&&r<=R){//被完全包含的情况
lazy[x]+=va;//打lazy标记
sum[x]+=1ll*(r-l+1)*va;//修改操作,将此点对应区间加上区间内包含数的个数*加上的va
return;
}
ll mid=(l+r)>>1;//同上,分为两个区间
//左区间[l,mid] 右区间[mid+1,r]
// #define lson l,mid,x<<1
// #define rson mid+1,r,(x<<1)+1
pushdown(x,mid-l+1,r-mid);//要修改的区间未被完全包含,下放标记,开始向下寻找
if (L<=mid){//要修改的区间有在左侧的部分
qxg(L,R,va,lson);
}
if (R>mid){//要修改的区间有在左侧的部分
qxg(L,R,va,rson);
}
pushup(x);//向上回溯,修改
}
int main(){
scanf("%lld %lld",&n,&q);
for (ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,n,1);
while(q--){
ll op;
scanf("%lld",&op);
if (op==1){
ll l,r,x;
scanf("%lld%lld%lld",&l,&r,&x);
qxg(l,r,x,1,n,1);
}
else{
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",qs(l,r,1,n,1));
}
}
return 0;
}