1. 程式人生 > 其它 >線段樹模板(區間修改+區間查詢)

線段樹模板(區間修改+區間查詢)

【問題描述】

  給定一個長為n的序列,有m次操作,每次操作對序列某段區間內所有數加上一個數或者詢問一段區間的和。

【程式】

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,a[500001],add[500001];
 5 long long sum[500001]; 
 6 
 7 void build(int k,int l,int r)    //建樹 
 8 {
 9     if (l==r)    //當前為葉節點 
10     {
11         sum[k]=a[l];
12         return ;
13 } 14 int mid=(l+r)>>1; 15 build(k*2,l,mid); //左子樹 16 build(k*2+1,mid+1,r); //右子樹 17 sum[k]=sum[k*2]+sum[k*2+1]; 18 } 19 20 void Add(int k,int l,int r,int v) //區間加值並更新 21 { 22 add[k]+=v; //打標記 23 sum[k]+=(long long)v*(r-l+1); //維護區間和 24 } 25 26 void pushdown(int
k,int l,int r,int mid) //標記下放 27 { 28 if (add[k]==0) //沒有標記 29 return ; 30 else 31 { 32 Add(k*2,l,mid,add[k]); //下傳到左子樹 33 Add(k*2+1,mid+1,r,add[k]); //下傳到右子樹 34 add[k]=0; //清零標記 35 } 36 } 37 38 long long query(int k,int l,int r,int x,int y) //
詢問 39 { 40 if (x<=l&&r<=y) 41 return sum[k]; 42 int mid=(l+r)>>1; 43 long long ans=0; 44 pushdown(k,l,r,mid); //下傳標記 45 if (x<=mid) 46 ans+=query(k*2,l,mid,x,y); 47 if (mid<y) 48 ans+=query(k*2+1,mid+1,r,x,y); 49 return ans; 50 } 51 52 void modify(int k,int l,int r,int x,int y,int v) //區間和 53 { 54 if (x<=l&&r<=y) 55 return Add(k,l,r,v); 56 int mid=(l+r)>>1; 57 pushdown(k,l,r,mid); //到達每一個結點都要下傳標記 58 if (x<=mid) 59 modify(k*2,l,mid,x,y,v); 60 if (mid<y) 61 modify(k*2+1,mid+1,r,x,y,v); 62 sum[k]=sum[k*2]+sum[k*2+1]; //更新下傳之後的最新值 63 } 64 65 int main() 66 { 67 scanf("%d%d",&n,&m); 68 for (int i=1;i<=n;i++) 69 scanf("%d",&a[i]); 70 build(1,1,n); //建樹 71 while (m--) 72 { 73 int op,x,y,v; 74 scanf("%d",&op); 75 if (op==1) //在x到y的區間內每個數加上v 76 { 77 scanf("%d%d%d",&x,&y,&v); 78 modify(1,1,n,x,y,v); 79 } 80 if (op==2) //查詢x到y的區間和 81 { 82 scanf("%d%d",&x,&y); 83 printf("%lld\n",query(1,1,n,x,y)); 84 } 85 } 86 return 0; 87 }

再附一份沒有註釋的程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,a[500001],add[500001];
 5 long long sum[500001]; 
 6 
 7 void build(int k,int l,int r)
 8 {
 9     if (l==r)    
10     {
11         sum[k]=a[l];
12         return ;
13     }
14     int mid=(l+r)>>1;
15     build(k*2,l,mid);    
16     build(k*2+1,mid+1,r);
17     sum[k]=sum[k*2]+sum[k*2+1]; 
18 }
19 
20 void Add(int k,int l,int r,int v)    
21 {
22     add[k]+=v;    
23     sum[k]+=(long long)v*(r-l+1); 
24 }
25 
26 void pushdown(int k,int l,int r,int mid)     
27 {    
28     if (add[k]==0)    
29         return ;
30     else
31     {
32         Add(k*2,l,mid,add[k]);    
33         Add(k*2+1,mid+1,r,add[k]);    
34         add[k]=0;    
35     }
36 }
37 
38 long long query(int k,int l,int r,int x,int y)    
39 {
40     if (x<=l&&r<=y)
41         return sum[k];
42     int mid=(l+r)>>1;
43     long long ans=0;
44     pushdown(k,l,r,mid);
45     if (x<=mid)
46         ans+=query(k*2,l,mid,x,y);
47     if (mid<y)
48         ans+=query(k*2+1,mid+1,r,x,y);
49     return ans;
50 }
51 
52 void modify(int k,int l,int r,int x,int y,int v)
53 {
54     if (x<=l&&r<=y)
55         return Add(k,l,r,v);
56     int mid=(l+r)>>1;
57     pushdown(k,l,r,mid);    
58     if (x<=mid)
59         modify(k*2,l,mid,x,y,v);
60     if (mid<y)
61         modify(k*2+1,mid+1,r,x,y,v);
62     sum[k]=sum[k*2]+sum[k*2+1];  
63 }
64 
65 int main()
66 {
67     scanf("%d%d",&n,&m);
68     for (int i=1;i<=n;i++)
69         scanf("%d",&a[i]);
70     build(1,1,n);
71     while (m--)
72     {
73         int op,x,y,v;
74         scanf("%d",&op);
75         if (op==1)
76         {
77             scanf("%d%d%d",&x,&y,&v);
78             modify(1,1,n,x,y,v);
79         }
80         if (op==2)
81         {
82             scanf("%d%d",&x,&y);
83             printf("%lld\n",query(1,1,n,x,y)); 
84         } 
85     } 
86     return 0;
87 }