1. 程式人生 > >WHYZOJ-#53 線段樹區間修改(線段樹)

WHYZOJ-#53 線段樹區間修改(線段樹)

namespace 標記 upd build out state long 輸入 std

【題目描述】:

如題,已知一個數列,你需要進行下面兩種操作:

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

【時間限制、數據範圍及描述】:

時間:1s 空間:128M

對於30%的數據:N<=8,M<=10

對於70%的數據:N<=1000,M<=10000

對於100%的數據:N<=100000,M<=100000

(數據保證在int64/long long數據範圍內)

感覺通過加和乘那一題,我的線段樹水平有了質的提升,還是那個原則,打延遲標記的時候當前節點也要更新,並且,只要需要訪問子節點,就一定要標記下傳,無論是查詢還是更新!!!
 1 #include "bits/stdc++.h"
 2 #define mem(a,b) memset(a,b,sizeof(a))
 3
#define lson rt<<1,l,m 4 #define rson rt<<1|1,m+1,r 5 using namespace std; 6 typedef long long LL; 7 const int MAX=100005; 8 int n,m; 9 LL sum[MAX*4],la[MAX*4]; 10 void PushUp(int rt){ 11 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 12 } 13 void PushDown(int rt,int l,int r){ 14 int
m=(l+r)>>1; 15 if (la[rt]!=0){ 16 la[rt<<1]+=la[rt];la[rt<<1|1]+=la[rt]; 17 sum[rt<<1]+=la[rt]*(m-l+1);sum[rt<<1|1]+=la[rt]*(r-m); 18 la[rt]=0; 19 } 20 } 21 void build(int rt,int l,int r){ 22 if (l==r){ 23 scanf("%lld",&sum[rt]); 24 la[rt]=0; 25 return; 26 }la[rt]=0; 27 int m=(l+r)>>1; 28 build(lson); 29 build(rson); 30 PushUp(rt); 31 } 32 void update(int rt,int l,int r,LL x,LL y,LL z){ 33 if (x<=l && r<=y){ 34 la[rt]+=z; 35 sum[rt]+=(r-l+1)*z; 36 return; 37 } 38 int m=(l+r)>>1; 39 PushDown(rt,l,r); 40 if (x<=m) 41 update(lson,x,y,z); 42 if (y>m) 43 update(rson,x,y,z); 44 PushUp(rt); 45 } 46 LL search(int rt,int l,int r,int x,int y){ 47 if (x<=l && r<=y) return sum[rt]; 48 LL an=0; 49 int m=(l+r)>>1; 50 PushDown(rt,l,r); 51 if (x<=m) 52 an+=search(lson,x,y); 53 if (y>m) 54 an+=search(rson,x,y); 55 return an; 56 } 57 int main(){ 58 freopen ("segtree.in","r",stdin); 59 freopen ("segtree.out","w",stdout); 60 int i,j; 61 LL x,y,z,w; 62 scanf("%d%d",&n,&m); 63 build(1,1,n); 64 for (i=1;i<=m;i++){ 65 scanf("%lld",&w); 66 if (w==1){ 67 scanf("%lld%lld%lld",&x,&y,&z); 68 update(1,1,n,x,y,z); 69 } 70 if (w==2){ 71 scanf("%lld%lld",&x,&y); 72 printf("%lld\n",search(1,1,n,x,y)); 73 } 74 } 75 return 0; 76 }

WHYZOJ-#53 線段樹區間修改(線段樹)