[模版]线段树入门
前言
线段树是OI中常用的数据结构,因为码量大,比较毒瘤,导致我以前学的时候没怎么在意,这都马上退役了,我才来补坑
之前学的时候,网上的代码都不符合个人的审美,一直在纠结学哪一种好,如果你也有这样的烦恼,请读完这篇文章,说不定我的码风可能适合你
一、
作为数据结构,线段树可以在 Ο(log n) 的时间复杂度完成一次操作,建树的过程则需要 Ο(n)
模板题一
题目连接 : https://www.acwing.com/problem/content/description/244/
这是最基础的线段树,当然有人会说你有 lazy_tag 还最基础吗? 但是请想一想,如果没有 lazy_tag,线段树的存在是非还有意义呢
诚然,我已经相信你已经看过很多模板了,但是如果你觉得之前看过的代码不够美观,也可大致浏览一下
Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 const int N=100002; 7 inline ll read() 8 { 9 char ch=getchar(); 10 ll x=0;bool f=false; 11 while (!isdigit(ch)) f^=!(ch^45),ch=getchar(); 12 while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 13 if (f) x=-x;return x; 14 } 15 int n,m; 16 char opt; 17 ll a[N]; 18 ll sum[N<<2],lazy[N<<2]; 19 inline void push_up(int root) 20 { 21 sum[root]=sum[root<<1]+sum[root<<1|1]; 22 } 23 inline void build(int root,int l,int r) 24 { 25 if (l==r) 26 { 27 sum[root]=a[l]; 28 return; 29 } 30 int mid=l+r>>1; 31 build(root<<1,l,mid); 32 build(root<<1|1,mid+1,r); 33 push_up(root); 34 } 35 inline void push_down(int root,int l,int r) 36 { 37 if (!lazy[root]) return; 38 int mid=l+r>>1; 39 lazy[root<<1]+=lazy[root]; 40 lazy[root<<1|1]+=lazy[root]; 41 sum[root<<1]+=(mid-l+1)*lazy[root]; 42 sum[root<<1|1]+=(r-mid)*lazy[root]; 43 lazy[root]=0; 44 } 45 inline void updata(int root,int L,int R,int v,int l,int r) 46 { 47 if (L<=l&&r<=R) 48 { 49 lazy[root]+=v; 50 sum[root]+=(r-l+1)*v; 51 return; 52 } 53 push_down(root,l,r); 54 int mid=l+r>>1; 55 if (L<=mid) 56 updata(root<<1,L,R,v,l,mid); 57 if (R>mid) 58 updata(root<<1|1,L,R,v,mid+1,r); 59 push_up(root); 60 } 61 inline ll query(int root,int L,int R,int l,int r) 62 { 63 if (L<=l&&r<=R) 64 return sum[root]; 65 66 push_down(root,l,r); 67 ll ans=0; 68 int mid=l+r>>1; 69 if (L<=mid) 70 ans+=query(root<<1,L,R,l,mid); 71 if (R>mid) 72 ans+=query(root<<1|1,L,R,mid+1,r); 73 push_up(root); 74 return ans; 75 } 76 int main() 77 { 78 n=read(),m=read(); 79 for (int i=1;i<=n;++i) 80 a[i]=read(); 81 build(1,1,n); 82 int l,r,d; 83 for (int i=1;i<=m;++i) 84 { 85 cin>>opt; 86 if (opt=='C') 87 { 88 l=read(),r=read(),d=read(); 89 updata(1,l,r,d,1,n); 90 } 91 if (opt=='Q') 92 { 93 l=read(),r=read(); 94 printf("%lld\n",query(1,l,r,1,n)); 95 } 96 } 97 return 0; 98 }
模板题二
题目连接 : https://www.luogu.org/problem/P3373
这道就比较进阶了,但是也是很基础的内容了
放在这里只是让大家取长补短,有觉得可以受用的地方就是我写这篇文章的意义
Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 const int N=100005; 7 inline ll read() 8 { 9 char ch=getchar(); 10 ll x=0;bool f=false; 11 while (!isdigit(ch)) f^=!(ch^45),ch=getchar(); 12 while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 13 if (f) x=-x;return x; 14 } 15 ll n,m,p; 16 ll a[N]; 17 ll sum[N<<2],add[N<<2],mul[N<<2]; 18 inline void push_up(int root) 19 { 20 sum[root]=(sum[root<<1]+sum[root<<1|1])%p; 21 } 22 inline void build(int root,int l,int r) 23 { 24 add[root]=0,mul[root]=1; 25 if (l==r) 26 { 27 sum[root]=a[l]; 28 return; 29 } 30 int mid=l+r>>1; 31 build(root<<1,l,mid); 32 build(root<<1|1,mid+1,r); 33 push_up(root); 34 } 35 inline void push_down(int root,int l,int r) 36 { 37 mul[root<<1]=(mul[root<<1]*mul[root])%p; 38 mul[root<<1|1]=(mul[root<<1|1]*mul[root])%p; 39 add[root<<1]=(add[root<<1]*mul[root])%p; 40 add[root<<1|1]=(add[root<<1|1]*mul[root])%p; 41 sum[root<<1]=(sum[root<<1]*mul[root])%p; 42 sum[root<<1|1]=(sum[root<<1|1]*mul[root])%p; 43 mul[root]=1; 44 int mid=l+r>>1; 45 add[root<<1]=(add[root<<1]+add[root])%p; 46 add[root<<1|1]=(add[root<<1|1]+add[root])%p; 47 sum[root<<1]=(sum[root<<1]+(mid-l+1)*add[root])%p; 48 sum[root<<1|1]=(sum[root<<1|1]+(r-mid)*add[root])%p; 49 add[root]=0; 50 } 51 inline void updata_add(int root,int L,int R,int v,int l,int r) 52 { 53 if (L<=l&&r<=R) 54 { 55 add[root]=(add[root]+v)%p; 56 sum[root]=(sum[root]+(r-l+1)*v)%p; 57 return; 58 } 59 if (mul[root]!=1||add[root]) 60 push_down(root,l,r); 61 int mid=l+r>>1; 62 if (L<=mid) 63 updata_add(root<<1,L,R,v,l,mid); 64 if (R>mid) 65 updata_add(root<<1|1,L,R,v,mid+1,r); 66 push_up(root); 67 } 68 inline void updata_mul(int root,int L,int R,int v,int l,int r) 69 { 70 if (L<=l&&r<=R) 71 { 72 mul[root]=(mul[root]*v)%p; 73 add[root]=(add[root]*v)%p; 74 sum[root]=(sum[root]*v)%p; 75 return; 76 } 77 if (mul[root]!=1||add[root]) 78 push_down(root,l,r); 79 int mid=l+r>>1; 80 if (L<=mid) 81 updata_mul(root<<1,L,R,v,l,mid); 82 if (R>mid) 83 updata_mul(root<<1|1,L,R,v,mid+1,r); 84 push_up(root); 85 } 86 inline ll query(int root,int L,int R,int l,int r) 87 { 88 if (L<=l&&r<=R) 89 return sum[root]%p; 90 if (mul[root]!=1||add[root]) 91 push_down(root,l,r); 92 ll ans=0; 93 int mid=l+r>>1; 94 if (L<=mid) 95 ans+=query(root<<1,L,R,l,mid); 96 if (R>mid) 97 ans+=query(root<<1|1,L,R,mid+1,r); 98 push_up(root); 99 return ans%p; 100 } 101 int main() 102 { 103 n=read(),m=read(),p=read(); 104 for (int i=1;i<=n;++i) 105 a[i]=read(); 106 build(1,1,n); 107 int opt,x,y,k; 108 while (m--) 109 { 110 opt=read(); 111 if (opt==1) 112 { 113 x=read(),y=read(),k=read(); 114 updata_mul(1,x,y,k,1,n); 115 } 116 else if (opt==2) 117 { 118 x=read(),y=read(),k=read(); 119 updata_add(1,x,y,k,1,n); 120 } 121 else if (opt==3) 122 { 123 x=read(),y=read(); 124 printf("%lld\n",query(1,x,y,1,n)); 125 } 126 } 127 return 0; 128 }
二、
我对关于线段树的知识什么都没有讲,一是因为自己本来就不太会讲,二是因为网上的大佬太多了,厉害的大有人在,我就不班门弄斧了