【模板】线段树 (线段树的懒惰标记)

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 k
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n, m,分别表示该数列数字的个数和操作的总个数。

第二行包含 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。

接下来 m 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

1.1 x y k:将区间 [x, y] 内每个数加上 k

2.2 x y:输出区间 [x, y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例

输入 #1
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出 #1
11
8
20

说明/提示

对于 30% 的数据:n8,m10。
对于 70% 的数据:n10^3,m10^4。
对于 100% 的数据:1n,m10^5。

保证任意时刻数列中任意元素的和在 [2^63,2^63] 内。


 find线段树新盲区!——线段树的懒惰标记

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 long long tree[300001],lazy[300001];
 7 long long sum,a[300001],n,m;
 8 int build(int i,int left,int right){
 9     if(left==right){
10         tree[i]=a[left];
11         return 0;
12     }
13     int mid=(left+right)/2;
14     build(i*2,left,mid);
15     build(i*2+1,mid+1,right);
16     tree[i]=tree[i*2]+tree[i*2+1];
17 }
18 int f(int p,int l,int r,int val){
19     lazy[p]+=val;
20     tree[p]+=val*(r-l+1);
21 }
22 int push_down(int p,int l,int r){
23     int mid=(l+r)/2;
24     f(p*2,l,mid,lazy[p]);
25     f(p*2+1,mid+1,r,lazy[p]);
26     lazy[p]=0;
27 }
28 int turn(int i,int left,int right,int b_l,int b_r,long long val){
29     if(b_l<=left&&right<=b_r){
30         tree[i]+=(right-left+1)*val;
31         lazy[i]+=val;//线段树的懒惰标记(可以提高速度)
32         return 0;
33     }
34     push_down(i,left,right);//更新左右节点(查询时遇到一次更新一次)
35     int mid=(left+right)/2;
36     if(b_l<=mid) turn(i*2,left,mid,b_l,b_r,val);
37     if(mid+1<=b_r) turn(i*2+1,mid+1,right,b_l,b_r,val);
38     tree[i]=tree[i*2]+tree[i*2+1];
39 }
40 int search(int i,int left,int right,int b_l,int b_r){
41     if(right<b_l||b_r<left) return 0;
42     if(b_l<=left&&right<=b_r){
43         sum+=tree[i];
44         return 0;
45     }
46     push_down(i,left,right);//这也是
47     int mid=(left+right)/2;
48     if(b_l<=mid) search(i*2,left,mid,b_l,b_r);
49     if(mid+1<=b_r) search(i*2+1,mid+1,right,b_l,b_r);
50 }
51 int main(){
52     //freopen("P3372_8.in","r",stdin);
53     scanf("%lld%lld",&n,&m);
54     for(register int i=1;i<=n;i++) scanf("%lld",&a[i]);
55     build(1,1,n);
56     while(m--){
57         int ooo;
58         scanf("%d",&ooo);
59         if(ooo==1){
60             int L,R;
61             long long K;
62             scanf("%d%d%lld",&L,&R,&K);
63             turn(1,1,n,L,R,K);
64             continue;
65         }
66         int L,R;
67         scanf("%d%d",&L,&R);
68         sum=0;
69         search(1,1,n,L,R);
70         printf("%lld\n",sum);
71     }
72 }

 

posted @ 2020-08-20 14:48  latent_Lin  阅读(249)  评论(0)    收藏  举报