/*
经典区间成段更新题目。
题意:给出一个长度n的数字序列,已经m个操作,Q操作给出l,r:访问区间[l,r]的数字和;
C操作给出l,r,x:将区间[l,r]内的所有数字都加上x。
Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15
*/
花了好些天研究ppt与别人的题解,不断的手动模拟才稍微理解lazy标记的熟络。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
#define LL __int64
struct node
{
int l,r;
LL lazy,sum; //lazy为延迟标记
int Len() { return r-l+1; }
int Mid() { return (l+r)>>1; }
}tree[3*maxn];
int a[maxn];
void Lazy(int p)
{
if(tree[p].lazy)
{
tree[p<<1].lazy+=tree[p].lazy;
tree[p<<1|1].lazy+=tree[p].lazy;
tree[p<<1].sum+=tree[p<<1].Len()*tree[p].lazy;
tree[p<<1|1].sum+=tree[p<<1|1].Len()*tree[p].lazy;
tree[p].lazy=0;
}
}
void BuildTree(int p,int l,int r)
{
tree[p].l=l,tree[p].r=r,tree[p].lazy=0;
if(l==r)
{
tree[p].sum=a[l];
return ;
}
int mid=(l+r)>>1;
BuildTree(p<<1,l,mid);
BuildTree(p<<1|1,mid+1,r);
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
void change(int p,int l,int r,int x)
{
if(tree[p].l==l&&tree[p].r==r)
{
tree[p].lazy+=x;
tree[p].sum+=x*tree[p].Len();
return;
}
Lazy(p); //标记下传
int mid=tree[p].Mid();
if(r<=mid)
change(p<<1,l,r,x);
else if(l>mid)
change(p<<1|1,l,r,x);
else
{
change(p<<1,l,mid,x);
change(p<<1|1,mid+1,r,x);
}
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
LL query(int p,int l,int r)
{
if(tree[p].l==l&&tree[p].r==r)
return tree[p].sum;
Lazy(p);
int mid=tree[p].Mid();
if(r<=mid)
return query(p<<1,l,r);
else if(l>mid)
return query(p<<1|1,l,r);
else
return query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
}
int main()
{
int n,Q,l,r,x,i;
char orde[3];
scanf("%d%d",&n,&Q);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
BuildTree(1,1,n);
while(Q--)
{
scanf("%s%d%d",orde,&l,&r);
if(l>r)
swap(l,r);
if(orde[0]=='C')
{
scanf("%d",&x);
change(1,l,r,x);
}
else
printf("%I64d\n",query(1,l,r));
}
return 0;
}