线段树

Posted codemaker-li

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。

今天写了线段树,

把以前不会的补了回来,

现在OK了,

一会附上线段树大模板,

各种操作都全了,

先简介一下,

总结出了几个道理:

1 区间加,区间替换的lazy下放不一样,

区间加对于tree[ i ]中的全部元素都 +=

区间替换就是直接赋值

2:lazy的含义是对于一个区间,这个区间完成一个操作,而该区间子区间没有进行该操作,

子区间所有元素 (包括最大值,最小值),都要加入lazy标记,

OK啦

下面是三个模板,最全啦,

操作格子1,是单点替换,区间查询区间和,最大值,最小值,

操作格子2,加上了区间替换为一个数,

操作格子3,加上了区间加一个数,

话不多说,

上代码, ( 代码里有注释,但不能直接提交,要弄明白 )

ps : 305行大代码,累死了

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <bits/stdc++.h>
  4 using namespace std;
  5 typedef long long ll;
  6 typedef unsigned long long ull;
  7 
  8 #define ls (t<<1)
  9 #define rs ((t<<1)|1)
 10 
 11 
 12 #define mk make_pair
 13 #define pb push_back
 14 #define fi first
 15 #define se second
 16 
 17 #define MAXN 500001
 18 
 19 struct tree{
 20     int l,r;
 21     ll sum,add,minn,maxx;
 22     //可以统计 区间和,区间加,区间最大/小
 23     #define l(x) t[x].l
 24     #define r(x) t[x].r
 25     #define sum(x) t[x].sum
 26     #define add(x) t[x].add
 27     #define maxx(x) t[x].maxx
 28     #define minn(x) t[x].minn
 29     tree() {
 30         l=r=0;
 31         sum=add=minn=maxx=0;
 32     }
 33 }t[MAXN*4];
 34 
 35 int a[MAXN];
 36 
 37 void build(int p,int l,int r) {
 38     l(p)=l;
 39     r(p)=r;
 40     add(p)=0;
 41     if (l==r) {
 42         sum(p)=a[l];
 43         maxx(p)=a[l];
 44         minn(p)=a[l];
 45         return;
 46     }
 47     int mid=(l+r)/2;
 48     build(p*2,l,mid);
 49     build(p*2+1,mid+1,r);
 50     sum(p)=sum(p*2)+sum(p*2+1);
 51     maxx(p)=max(maxx(p*2),maxx(p*2+1));
 52     minn(p)=min(minn(p*2),minn(p*2+1));
 53 }
 54 
 55 void spread1(int p) {
 56     //lazy标记下放与清除 
 57     //这里lazy用于区间加一个数 
 58     if (add(p)) {
 59         sum(p*2)+=add(p)*(r(p*2)-l(p*2)+1);
 60         maxx(p*2)+=add(p);
 61         minn(p*2)+=add(p);
 62         //更新左节点 
 63         sum(p*2+1)+=add(p)*(r(p*2+1)-l(p*2+1)+1);
 64         maxx(p*2+1)+=add(p);
 65         minn(p*2+1)+=add(p);
 66         //更新右节点 
 67         add(p*2)+=add(p);
 68         //左节点下放lazy 
 69         add(p*2+1)+=add(p);
 70         //右节点下放lazy 
 71         add(p)=0;
 72         //lazy清空 
 73     }
 74 }
 75 void spread2(int p) {
 76     //lazy标记下放与清除 
 77     //这里lazy用于区间替换为一个数 
 78     if (add(p)) {
 79         sum(p*2)=add(p)*(r(p*2)-l(p*2)+1);
 80         maxx(p*2)=add(p);
 81         minn(p*2)=add(p);
 82         //更新左节点 
 83         sum(p*2+1)=add(p)*(r(p*2+1)-l(p*2+1)+1);
 84         maxx(p*2+1)=add(p);
 85         minn(p*2+1)=add(p);
 86         //更新右节点 
 87         add(p*2)=add(p);
 88         //左节点下放lazy 
 89         add(p*2+1)=add(p);
 90         //右节点下放lazy 
 91         add(p)=0;
 92         //lazy清空 
 93     }
 94 }
 95 
 96 void change1(int p,int l,int r,int d) {
 97     //l 到 r 均 +d 
 98     if (l<=l(p)&&r>=r(p)) {
 99         add(p)+=d;
100         sum(p)+=(long long)d*(r(p)-l(p)+1);
101         maxx(p)+=d;
102         minn(p)+=d;
103         return;
104     }
105     spread1(p);
106     //spread2(p);
107     int mid=(l(p)+r(p))/2;
108     if (l<=mid) change1(p*2,l,r,d);
109     if (r>mid) change1(p*2+1,l,r,d);
110     sum(p)=sum(p*2)+sum(p*2+1);
111     maxx(p)=max(maxx(p*2),maxx(p*2+1));
112     minn(p)=min(minn(p*2),minn(p*2+1));
113 }
114 
115 void change3(int p,int l,int r,int d) {
116     // l~r 均替换为 d
117     if (l<=l(p)&&r>=r(p)) {
118         add(p)=d;
119         sum(p)=(long long)d*(r(p)-l(p)+1);
120         maxx(p)=d;
121         minn(p)=d;
122         return;
123     }
124     //spread1(p);
125     spread2(p);
126     int mid=(l(p)+r(p))/2;
127     if (l<=mid) change3(p*2,l,r,d);
128     if (r>mid) change3(p*2+1,l,r,d);
129     sum(p)=sum(p*2)+sum(p*2+1);
130     maxx(p)=max(maxx(p*2),maxx(p*2+1));
131     minn(p)=min(minn(p*2),minn(p*2+1)); 
132 }
133 
134 void change2(int p,int x,int v) {
135     //把 a[x] 值改为 v
136     if (l(p)==r(p)) {
137         //叶子节点直接赋值 
138         sum(p)=v;
139         maxx(p)=v;
140         minn(p)=v;
141         return;
142     } 
143     spread1(p);
144     //spread2(p);
145     int mid=(l(p)+r(p))/2;
146     if (x<=mid) change2(p*2,x,v);
147     else change2(p*2+1,x,v);
148     sum(p)=sum(p*2)+sum(p*2+1);
149     maxx(p)=max(maxx(p*2),maxx(p*2+1));
150     minn(p)=min(minn(p*2),minn(p*2+1));
151 }
152 
153 
154 ll asksum(int p,int l,int r) {
155     //查询 l~r 的和 
156     if (l<=l(p)&&r>=r(p)) return sum(p);
157     //spread1(p);
158     spread2(p);
159     int mid=(l(p)+r(p))/2;
160     ll val=0;
161     if (l<=mid) val+=asksum(p*2,l,r);
162     if (r>mid) val+=asksum(p*2+1,l,r);
163     return val;
164 }
165 
166 ll askmax(int p,int l,int r) {
167     //查询 l~r 的最大
168     if (l<=l(p)&&r>=r(p)) return maxx(p);
169     //spread1(p);
170     spread2(p);
171     int mid=(l(p)+r(p))/2;
172     ll val=-(1<<30);
173     if (l<=mid) val=max(val,askmax(p*2,l,r));
174     if (r>mid) val=max(val,askmax(p*2+1,l,r));
175     return val;
176 }
177 
178 ll askmin(int p,int l,int r) {
179     //查询 l~r 的最小
180     if (l<=l(p)&&r>=r(p)) return minn(p);
181     //spread(p);
182     spread2(p);
183     int mid=(l(p)+r(p))/2;
184     ll val=(1<<30);
185     if (l<=mid) val=min(val,askmin(p*2,l,r));
186     if (r>mid) val=min(val,askmin(p*2+1,l,r));
187     return val;
188 }
189 
190 /*
191 int n,m;
192 char c;
193 //操作格子1 
194 int main() {
195     scanf("%d%d",&n,&m);
196     for (int i=1;i<=n;i++) {
197         scanf("%d",&a[i]);
198     }
199     build(1,1,n);
200     for (int i=1,x,y;i<=m;i++) {
201         cin>>c;
202         scanf("%d%d",&x,&y);
203         if (c==‘Q‘) {
204             ll ansmax=0;
205             ll ansmin=0;
206             ll anssum=0;
207             ansmax=askmax(1,x,y);
208             ansmin=askmin(1,x,y);
209             anssum=asksum(1,x,y);
210             printf("%lld %lld %lld
",ansmax,ansmin,anssum);
211         }
212         if (c==‘U‘) {
213             change2(1,x,y);
214         }
215     }
216 
217     return 0;
218 }
219 */
220 
221 /*
222 int n,m;
223 char op[6];
224 //操作格子3 
225 int main () {
226     scanf("%d%d",&n,&m);
227     for (int i=1;i<=n;i++) {
228         scanf("%d",&a[i]);
229     }
230     build(1,1,n);
231     for (int i=1;i<=m;i++) {
232         cin>>op;
233         if (op[0]==‘S‘) {
234             int x,y;
235             scanf("%d%d",&x,&y);
236             ll ans=0;
237             ans=asksum(1,x,y);
238             printf("%lld
",ans);
239         }
240         if (op[0]==‘A‘) {
241             int x,y,z;
242             scanf("%d%d%d",&x,&y,&z);
243             change1(1,x,y,z);
244         }
245         if (op[0]==‘M‘&&op[1]==‘A‘) {
246             int x,y;
247             scanf("%d%d",&x,&y);
248             ll ans=0;
249             ans=askmax(1,x,y);
250             printf("%lld
",ans);
251         }
252         if (op[0]==‘M‘&&op[1]==‘I‘) {
253             int x,y;
254             scanf("%d%d",&x,&y);
255             ll ans=0;
256             ans=askmin(1,x,y);
257             printf("%lld
",ans);
258         }
259     }
260     
261     return 0;
262 }
263 */
264 
265 /*
266 int n,m;
267 char op[10];
268 int main () {
269     scanf("%d%d",&n,&m);
270     for (int i=1;i<=n;i++) {
271         scanf("%d",&a[i]);
272     }
273     build(1,1,n);
274     for (int i=1,x,y,z;i<=m;i++) {
275         cin>>op;
276         if (op[0]==‘S‘) {
277             scanf("%d%d",&x,&y);
278             ll ans=0;
279             ans=asksum(1,x,y);
280             printf("%lld
",ans);
281         }
282         if (op[0]==‘U‘) {
283             scanf("%d%d%d",&x,&y,&z);
284             change3(1,x,y,z);
285         }
286         if (op[0]==‘M‘&&op[1]==‘A‘) {
287             scanf("%d%d",&x,&y);
288             ll ans=0;
289             ans=askmax(1,x,y);
290             printf("%lld
",ans);
291         }
292         if (op[0]==‘M‘&&op[1]==‘I‘) {
293             scanf("%d%d",&x,&y);
294             ll ans=0;
295             ans=askmin(1,x,y);
296             printf("%lld
",ans);
297         }
298     }
299     return 0;
300 }
301 */
302 
303 int main () {
304     return 0;
305 }

 

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树