題面
【題目描述】
你有一些整數,和一些操作與詢問需要處理
【輸入】
第一行:,,.
第二行:個整數,
接下來:行,表示操作與詢問
表示,區間[]全部增加
表示求區間[]的和
【輸出】
每個詢問一個結果,一行。
【樣例輸入】
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;
}