因为忘了把lazy tag置零,找了一晚上的bug终于AC了QWQ
#include<bits/stdc++.h>
#define ll long long
#define maxn 20000000
using namespace std;
ll n, m, a[maxn];
struct tree{
ll l, r, val, tag;//l左端点, r右端点, val区间值, tag懒标记 (lazy tag)
}tr[maxn];
//向下更新
void down(ll p){
ll mid = (tr[p].l + tr[p].r)>>1;
//给左右孩子加上双亲的懒标记
tr[p<<1].tag += tr[p].tag; //p<<1相当于p*2
tr[p<<1|1].tag += tr[p].tag; //p<<1|1相当于p*2+1
//根据懒标记更新左右孩子的区间值
tr[p<<1].val += tr[p].tag * (mid-tr[p].l+1);
tr[p<<1|1].val += tr[p].tag * (tr[p].r-mid);
//左右孩子更新完毕,将双亲的懒标记归零
tr[p].tag = 0;
}
//向上更新
void up(ll p){
//根据左右孩子的区间值更新双亲结点的区间值
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
//初始化建树
void buildTree(ll p, ll l, ll r){
tr[p].l = l, tr[p].r = r, tr[p].tag = 0, tr[p].val = 0;
if(l==r){
tr[p].val = a[l];
return;
}
ll mid = (l+r)>>1; //相当于(l+r)/2
buildTree(p<<1, l, mid); //左孩子
buildTree(p<<1|1, mid+1, r);//有孩子
up(p);
}
//区间修改 (p为tr数组下标,在[l, r] + w)
void add(ll p, ll l, ll r, ll w){
if(tr[p].l>=l&&tr[p].r<=r){ //若tr[p]在[l, r]修改范围内
tr[p].tag += w;
tr[p].val += w * (tr[p].r - tr[p].l + 1);
return;
}
down(p);
ll mid = (tr[p].r+tr[p].l)>>1;
if(l<=mid)
add(p<<1, l, r, w);
if(r>mid)
add(p<<1|1, l, r, w);
up(p);
}
//获取[l, r]区间的和 (p为tr数组下标)
ll get(ll p, ll l, ll r){
ll ans = 0;
if(tr[p].l>=l&&tr[p].r<=r)//若tr[p]在[l, r]求和范围内
return tr[p].val;
down(p);
ll mid = (tr[p].r+tr[p].l)>>1;
if(l<=mid)
ans += get(p<<1, l, r);
if(r>mid)
ans += get(p<<1|1, l, r);
return ans;
}
//调试用的打印tr数组
void printTree(){
printf("\n");
for(ll i=1; i<=2*n-1; i++)
printf("%lld %lld %lld %lld\n", tr[i].l, tr[i].r, tr[i].val, tr[i].tag);
printf("\n");
}
int main(){
int t;
ll x, y, k;
cin>>n>>m;
for(ll i=1; i<=n; i++)
scanf("%lld", &a[i]);
buildTree(1, 1, n);
for(ll i=0; i<m; i++){
scanf("%d", &t);
if(t==1){
scanf("%lld %lld %lld", &x, &y, &k);
add(1, x, y, k);
}else{
scanf("%lld %lld", &x, &y);
printf("%lld\n", get(1, x, y));
}
}
return 0 ;
}