线段树学习笔记(初级:只支持区间加、区间求和)

匿名 (未验证) 提交于 2019-12-03 00:12:02

研究了很长时间线段树的理论,发现打过一遍代码就啥都懂了

简单来说,线段树是基于分治对区间进行快速修改的,所以时间效率很高

然后就是代码(洛谷太坑,query里面的ans也要开long long)

 1 #include <cstdio>  2 #include <cstring>  3 #include <iostream>  4 #include <algorithm>  5 using namespace std;  6 typedef long long ll;  7 const int N = 1e5 + 5;  8 ll addv[N*4],sumv[N*4],a[N];  9 int n,m; 10 inline int read() 11 { 12     int x=0,w=1; char c=getchar(); 13     while (c>'9'|| c<'0') {if(c=='-') w=-1; c=getchar();} 14     while (c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } 15     return w*x; 16 } 17 void pushup(int k) 18 { 19     sumv[k]=sumv[k<<1]+sumv[k<<1|1]; 20 } 21 inline void build(int o,int l,int r)//建树 22 { 23     if (l==r) {sumv[o]=a[l]; return ;} 24     int mid=(l+r)>>1;//分治操作 25     build(o<<1,l,mid); 26     build(o<<1|1,mid+1,r); 27     pushup(o); 28 } 29 void pushdown(int o,int l,int r)//玄学的pushdown(由树上操作推导而来) 30 { 31     if (addv[o]==0) return ; 32     addv[o<<1]+=addv[o]; 33     addv[o<<1|1]+=addv[o]; 34     int mid= (l+r)>>1; 35     sumv[o<<1]+=addv[o]*(mid-l+1); 36     sumv[o<<1|1]+=addv[o]*(r-mid); 37     addv[o]=0; 38 } 39 void puttag(int o,int l,int r,ll v)//lazytag操作,懒标记 40 { 41     addv[o]+=v; 42     sumv[o]+=(r-l+1)*v; 43 } 44 void modify(int o,int l,int r,int ql,int qr,ll v)//区间修改 45 { 46     if (ql<=l&&qr>=r) {puttag(o,l,r,v); return ;} 47     int ans=0,mid=(l+r)>>1; 48     pushdown(o,l,r);//这里的pushdown不能忘了 49     if(ql<=mid) modify(o<<1,l,mid,ql,qr,v); 50     if(qr>mid) modify(o<<1|1,mid+1,r,ql,qr,v); 51     pushup(o);     52 } 53 ll query(int o,int l,int r,int ql,int qr)//区间查询 54 { 55     if (ql<=l&&qr>=r) return sumv[o]; 56     pushdown(o,l,r); 57     ll ans=0; 58     int mid=(l+r)>>1; 59     if (ql<=mid) ans+=query(o<<1,l,mid,ql,qr); 60     if (qr>mid) ans+=query(o<<1|1,mid+1,r,ql,qr); 61     return ans; 62 } 63 int main() 64 { 65     n=read(); m=read();     66     for(int i=1;i<=n;++i) 67         scanf("%lld",&a[i]); 68     build(1,1,n); 69     while(m--) 70     { 71         int opt,l,r; 72         ll val; 73         opt=read(); 74         if (opt==1) l=read(),r=read(),scanf("%lld",&val),modify(1,1,n,l,r,val); 75         else l=read(),r=read(),printf("%lld\n",query(1,1,n,l,r)); 76     } 77     return 0; 78 }

To be continued...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!