[模版]线段树入门

前言

  线段树是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 }

二、

  我对关于线段树的知识什么都没有讲,一是因为自己本来就不太会讲,二是因为网上的大佬太多了,厉害的大有人在,我就不班门弄斧了

  如果我的代码对你有可取之处的话,那么我写这篇文章的目的也就达到了,感谢

posted @ 2019-11-06 19:51  Snowindfly  阅读(74)  评论(0编辑  收藏  举报