题面
【题目描述】
你有一些整数,和一些操作与询问需要处理
【输入】
第一行:,,.
第二行:个整数,
接下来:行,表示操作与询问
表示,区间[]全部增加
表示求区间[]的和
【输出】
每个询问一个结果,一行。
【样例输入】
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
【样例输出】
4
55
9
15
算法分析
线段树模板题目
区间修改。区间修改需要添加lazy标记。
参考程序
#include<iostream>
#include<cstdio>
#define N 100010
using namespace std;
int n,m;
long long a[N],lazy[4*N],s[4*N]; //4倍n
void built(int k,int l,int r)
{
if(l==r) {s[k]=a[l];return;}
int mid=(l+r)/2;
built(2*k,l,mid);
built(2*k+1,mid+1,r);
s[k]=s[k*2]+s[k*2+1];
}
void pushdown(int k,int l,int r) //标记下传
{
if(lazy[k]==0) return;
int mid=(l+r)/2;
s[2*k]+=(mid-l+1)*lazy[k]; //左孩子更新
lazy[2*k]+=lazy[k];
s[2*k+1]+=(r-mid)*lazy[k]; //右孩子更新
lazy[2*k+1]+=lazy[k];
lazy[k]=0;q //自身清0
}
void update(int k,int l,int r,int x,int y,long long v) //区间更新
{
if(y<l||x>r) return;
if(x<=l&&r<=y)
{
s[k]+=(r-l+1)*v;
lazy[k]+=v;
return;
}
pushdown(k,l,r); //标记下传,将没有更新的先更新再修改
int mid=(l+r)/2;
update(2*k,l,mid,x,y,v);
update(2*k+1,mid+1,r,x,y,v);
s[k]=s[k*2]+s[k*2+1];
}
long long ask(int k,int l,int r,int x,int y) //区间询问
{
if(y<l||x>r) return 0;
if(x<=l&&r<=y) return s[k];
pushdown(k,l,r); //标记下传,将没有更新的更新再返回答案
int mid=(l+r)/2;
return ask(k*2,l,mid,x,y)+ask(k*2+1,mid+1,r,x,y);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
built(1,1,n);
char c[10];
int x,y;
long long z;
while(m--)
{
scanf("%s",c);
if(c[0]=='C')
{
scanf("%d%d%lld",&x,&y,&z);
update(1,1,n,x,y,z);
}
if(c[0]=='Q')
{
scanf("%d%d",&x,&y);
printf("%lld\n",ask(1,1,n,x,y));
}
}
return 0;
}