【線段樹】區間求和+區間修改(區間加)
阿新 • • 發佈:2018-12-24
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,a[1000004];
struct data{int l,r,val,lazy,len;}tr[2*1000004];
void build(int k,int s,int t) {//建樹
tr[k].l=s;tr[k].r=t;tr[k].len=t-s+1;
if(s==t) {tr[k].val=a[s];return;}
int mid=(s+t)>>1;
build(k<<1,s,mid);
build(k<<1 |1,mid+1,t);
tr[k].val=tr[k<<1].val+tr[k<<1|1].val;
}
void pushdown(int k){//pushdown操作
if(!tr[k].lazy) return;
int p=tr[k].lazy;
tr[k<<1].lazy+=p;
tr[k<<1|1].lazy+=p;
tr[k<<1].val+=tr[k<<1].len*p;
tr[k<<1|1].val+=tr[k<<1|1].len*p ;
tr[k].lazy=0;
}
void update(int k,int l,int r,int addval){//區間修改
int ll=tr[k].l,rr=tr[k].r;
if(ll>=l && rr<=r){
tr[k].lazy+=addval;
tr[k].val+=tr[k].len*addval;
return;
}
int mid=(ll+rr)>>1;
if (tr[k].lazy) pushdown(k);
if(l<=mid) update(k<<1 ,l,min(r,mid),addval);
if(r>mid) update(k<<1|1,max(l,mid+1),r,addval);
tr[k].val=tr[k<<1].val+tr[k<<1|1].val;
}
int query(int k,int x,int y){//區間求和
int ll=tr[k].l,rr=tr[k].r;
if(x==ll && y==rr) return tr[k].val;
int mid=(ll+rr)>>1;
if (tr[k].lazy) pushdown(k);
if(y<=mid) return query(k<<1,x,y);
else if(x>mid) return query(k<<1|1,x,y);
else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++){
int flag;scanf("%d",&flag);
int x,y,z;scanf("%d%d",&x,&y);
if(flag==1) scanf("%d",&z),update(1,x,y,z);
else printf("%d\n",query(1,x,y));
}
return 0;
}
輸入格式:
第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。
第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。
接下來M行每行包含3或4個整數,表示一個操作,具體如下:
操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k
操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和
輸出格式:
輸出包含若干行整數,即為所有操作2的結果。
輸入樣例:
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
輸出樣例:
11
8
20