1. 程式人生 > >【線段樹】區間求和+區間修改(區間加)

【線段樹】區間求和+區間修改(區間加)

#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