1 build(1,1,n)
2 if(t[u]!=0)
3 tr[u]=c*(r-l+1) 而不是tr[u]
4 if(l<=mid) 而不是s<l
if(r>=mid+1) 而不是e>r
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
typedef long long ll;
ll a[N],tr[4*N],t[4*N];
void pushup(int u)
{
tr[u]=tr[u<<1]+tr[u<<1|1];
}
void pushdown(int u,int l,int r)
{
if(t[u]!=0)
{
int mid=l+r>>1;
tr[u<<1]+=t[u]*(mid-l+1);
tr[u<<1|1]+=t[u]*(r-mid);
t[u<<1]+=t[u];
t[u<<1|1]+=t[u];
t[u]=0;
}
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]=a[l];
return;
}
//能走到这的说明不是叶子节点,需要通过叶子节点更新自己
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
ll sum(int u,int l,int r,int s,int e)
{
if(s<=l&&e>=r)return tr[u];
int mid=l+r>>1;
pushdown(u,l,r);//因为要把更新的懒标记传给子节点 让子节点更新之后才能用子节点更新父节点
//更改的区间[3,6]和查询的区间[2,4]只有一部分是交集的时候 更改的区间可能在[3,4]就不继续下传了
//查询的时候[1,10]->[1,6]->[1,3][4,6]分别只覆盖了点3和点4,所以需要进一步拆为[1,2],[3],[4,5],[6]->[2] [3] [4]的子区间
//把[3,6]的tag传下[3][4]去后更新[2,4]才能真正利用到了tag
ll res = 0;
if(s<=mid)res+=sum(u<<1,l,mid,s,e);
if(e>=mid+1)res+=sum(u<<1|1,mid+1,r,s,e);
return res;
}
void update(int u,int l,int r,int s,int e,ll c)
{
if(s<=l&&e>=r)//是[s,e]之间的节点就直接更新
{
tr[u]+=c*(r-l+1);
t[u]+=c;
return ;
}
//能走到这的说明不是叶子节点,需要通过叶子节点更新自己
int mid = l+r>>1;
pushdown(u,l,r);
if(s<=mid)update(u<<1,l,mid,s,e,c);
if(e>=mid+1)update(u<<1|1,mid+1,r,s,e,c);
pushup(u);//不是[s,e]之间的节点就需要通过子节点更新父节点
//
}
int main()
{
int m,n;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
for(int i=0;i<m;i++)
{
int s,e;
ll c;
char op[2];
scanf("%s %d %d",&op,&s,&e);
if(op[0]=='Q')
{
printf("%lld\n",sum(1,1,n,s,e));
}
else
{
scanf("%lld",&c);
update(1,1,n,s,e,c);
}
}
return 0;
}