前言
线段树是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 }
二、
我对关于线段树的知识什么都没有讲,一是因为自己本来就不太会讲,二是因为网上的大佬太多了,厉害的大有人在,我就不班门弄斧了