模板线段树+懒操作

Posted 小蒟蒻

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板线段树+懒操作相关的知识,希望对你有一定的参考价值。

题目描述

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

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的结果。

输入输出样例

输入样例#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

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^,保证在int64/long long数据范围内)

 

线段树有区间修改及求和的功能。其中区间修改包括单点修改和成段替换。当数据比较大的时候,有时需要用到懒操作来降低时间复杂度。

重要步骤在代码里都有注释:

技术分享图片
 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 #define LL long long
 8 #define lson l,m,rt<<1   //这里一定要注意:不是1(数字)~m而是l(字母)~m!!
 9 #define rson m+1,r,rt<<1|1  //同上,不是n而是r!
10 using namespace std;
11 const int MAXN=100000;
12 int n,m;
13 LL sum[MAXN<<2],pl[MAXN<<2];
14 void pushup(int rt)
15 {
16     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
17 }
18 void build(int l,int r,int rt)
19 {
20     pl[rt]=0;
21     if(l==r)
22     {
23         scanf("%lld",&sum[rt]);
24         return ;
25     }
26     int m=(l+r)>>1;
27     build(lson);
28     build(rson);
29     pushup(rt);
30 }
31 void pushdown(int rt,int len)  //懒操作:只记录当前一步需要更新的数值
32 {
33     if(pl[rt])  //如果当前有之前标记的数值
34     {
35         pl[rt<<1]+=pl[rt];  //父区间更新,他的左右子区间 也会更新
36         pl[rt<<1|1]+=pl[rt];
37         sum[rt<<1]+=pl[rt]*(len-(len>>1));  //左子树更新了几个
38         sum[rt<<1|1]+=pl[rt]*(len>>1);
39         pl[rt]=0;//这里一定要记得赋零
40     }
41 }
42 void update(int L,int R,int add,int l,int r,int rt)
43 {
44     if(L<=l && r<=R)
45     {
46         pl[rt]+=add;  //懒标记
47         sum[rt]+=(LL)add*(r-l+1);
48         return ;
49     }
50     int m=(l+r)>>1;
51     pushdown(rt,r-l+1);
52     if(L<=m) update(L,R,add,lson);
53     if(m+1<=R) update(L,R,add,rson);
54     pushup(rt);    
55 }
56 LL query(int L,int R,int l,int r,int rt)  
57 {
58     if(L<=l && r<=R) return sum[rt];
59         pushdown(rt,r-l+1);   //检查有没有上一步留下的懒标记
60     int m=(l+r)>>1;
61     LL ret=0;
62     if(L<=m) ret+=query(L,R,lson);
63     if(R>m) ret+=query(L,R,rson);
64     return ret;
65 }
66 
67 int main()
68 {
69     scanf("%d%d",&n,&m);
70     build(1,n,1);
71     for(int i=1;i<=m;i++)
72     {
73         int c;
74         scanf("%d",&c);
75         if(c==1)
76         {
77             int x,y,k;
78             scanf("%d%d%d",&x,&y,&k);
79             update(x,y,k,1,n,1);
80         }
81         else
82         {
83             int x0,y0;
84             scanf("%d%d",&x0,&y0);
85             printf("%lld\n",query(x0,y0,1,n,1));
86         }
87     }
88     return 0;
89 }
Segment tree(1)

本题用到了成段替换及求和的操作。

以上是关于模板线段树+懒操作的主要内容,如果未能解决你的问题,请参考以下文章

线段树模板题pushup+pushdown操作

[模板]洛谷T3373 线段树 模板2

P3372 模板线段树 1

[模板]洛谷T3372 线段树 模板1

P3372 模板线段树 1

P3372 模板线段树 1