【線段樹模板】區間修改區間求和
阿新 • • 發佈:2018-12-11
蒟蒻線上段樹的路上繼續前進,lazy的出題人的奇思妙想——延遲標記震撼了他。。
線段樹模板題(二)——區間修改與查詢區間和:區間修改區間求和
【題目描述】
如題,已知一個數列,你需要進行下面兩種操作:
1.將某區間每一個數加上x
2.求出某區間每一個數的和
【輸入】
第一行包含兩個整數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
程式碼:
#include<bits/stdc++.h> using namespace std; #define lc (p<<1) #define rc (p<<1|1) long long n,m,a[100010]; struct node{ int l,r,lazy;//延遲標記——lazy long long sum; }T[100010*4]; void pushnow(long long p,long long v){ T[p].sum+=(T[p].r-T[p].l+1)*v; T[p].lazy+=v; } void pushdown(long long p){ if(T[p].lazy){ pushnow(lc,T[p].lazy); pushnow(rc,T[p].lazy); T[p].lazy=0; } } void pushup(long long p){ T[p].sum=T[lc].sum+T[rc].sum; } void build(long long p,long long l,long long r){//建樹 T[p].l=l; T[p].r=r; if(l==r){ T[p].sum=a[l]; T[p].lazy=0; return ; } long long mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r); pushup(p); } void update(long long p,long long ql,long long qr,long long v){//向上維護 if(ql<=T[p].l&&T[p].r<=qr){ pushnow(p,v); return ; } long long mid=(T[p].l+T[p].r)>>1; pushdown(p); if(ql<=mid) update(lc,ql,qr,v); if(qr>mid) update(rc,ql,qr,v); pushup(p); } long long query(long long p,long long ql,long qr){//區間求和 if(ql<=T[p].l&&qr>=T[p].r) return T[p].sum; long long mid=(T[p].l+T[p].r)>>1; pushdown(p); long long ans=0; if(ql<=mid) ans+=query(lc,ql,qr); if(qr>mid) ans+=query(rc,ql,qr); pushup(p); return ans; } int main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } build(1,1,100100); for(long long i=1;i<=m;i++){ long long p; scanf("%lld",&p); if(p==1){ long long x,y,k; scanf("%lld%lld%lld",&x,&y,&k); update(1,x,y,k); } if(p==2){ long long x,y; scanf("%lld%lld",&x,&y); printf("%lld\n",query(1,x,y)); } } return 0; }