模板线段树+懒操作
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 }
本题用到了成段替换及求和的操作。
以上是关于模板线段树+懒操作的主要内容,如果未能解决你的问题,请参考以下文章