大牛博客 https://blog.csdn.net/zearot/article/details/48299459
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <cmath>
#include <set>
//#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[110000]; //计算区间
ll tr[1100000]; //线段树区间 a的四倍 怕出错开十倍
ll lazy[1100000];//懒惰数组
void pushup(ll rt) //更新线段树rt的值
{
tr[rt] = tr[rt<<1] +tr[rt<<1|1];
}
void build(ll l,ll r,ll rt) //建树 l r 为当前线段树rt 代表的区间和
{
if(l==r)
{
tr[rt] = a[l];
return ;
}
ll m =(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(ll rt,ll ln,ll rn) //更新rt
{
if(lazy[rt]) //判断当前区间是否给标记
{
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
tr[rt<<1] += lazy[rt]*ln;
tr[rt<<1|1] += lazy[rt]*rn;
lazy[rt] = 0;
}
}
void updata1(ll L,ll c,ll l,ll r,ll rt) //修改点 L需要修改的点 lr当前区间
{
if(l==r)
{
tr[rt] += c;
return ;
}
ll m = (l+r)>>1;
if(L <= m) updata1(L,c,l,m,rt<<1);
else updata1(L,c,m+1,r,rt<<1|1);
pushup(rt);
}
void updata(ll L,ll R,ll c,ll l,ll r,ll rt)//修改区间 L R 为需要修改的区间
{ // l r 为当前线段树区间 c 为需要改动的大小
if(L <= l&& r <= R)
{
tr[rt] += c*(r-l+1);
lazy[rt] += c;
return ;
}
ll m = (l+r)>>1;
pushdown(rt,m-l+1,r-m); //改动点去掉
if(L <= m) updata(L,R,c,l,m,rt<<1);
if(R > m) updata(L,R,c,m+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt) //查询 L R需要查询区间 lr当前区间
{
if(L<=l&&r <= R)
{
return tr[rt];
}
ll m = (l+r)>>1;
pushdown(rt,m-l+1,r-m);//改动点去掉这句
ll ans = 0;
if(L <= m) ans+=query(L,R,l,m,rt<<1);
if(R > m) ans += query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
ll n,m,i,j,t,l,w,r;
char c;
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,n,1);
memset(lazy,0,sizeof(lazy));
while(m--)
{
getchar();
scanf("%c",&c);
//printf("%c\n",c);
if(c=='Q')
{
scanf("%lld%lld",&l,&r);
ll ans = query(l,r,1,n,1);
printf("%lld\n",ans);
}
else if(c=='C')
{
scanf("%lld%lld%lld",&l,&r,&w);
updata(l,r,w,1,n,1);
}
}
return 0;
}