研究了很长时间线段树的理论,发现打过一遍代码就啥都懂了
简单来说,线段树是基于分治对区间进行快速修改的,所以时间效率很高
然后就是代码(洛谷太坑,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...