2021暑假 线段树&树状数组&ST表 专题(1)

前言

  嘿,我李某人又回来啦,今天发一下jzoj的比赛吧!

T1:【线段树】最大值

在N(1<=N<=100000)个数A1…An组成的序列上进行M(1<=M<=100000)次操作,操作有两种:
(1)1 x y:表示修改A[x]为y;
(1)2 x y:询问x到y之间的最大值。
输入
第一行输入N(1<=N<=100000),表示序列的长度,接下来N行输入原始序列;接下来一行输入M(1<=M<=100000)表示操作的次数,接下来M行,每行为1 x y或2 x y
输出
对于每个操作(2)输出对应的答案。
 
这是一道很明显的板子题
注意细节就行了
上~代~码~
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,a[1000010],m,f[4000010],d,x,y,maxn;
 4 void bt(int i,int x,int y){
 5     if(x==y){
 6         f[i]=a[x];
 7         return;
 8     }
 9     int m=(x+y)/2;
10     bt(2*i,x,m);
11     bt(2*i+1,m+1,y);
12     f[i]=max(f[2*i],f[2*i+1]);
13 }
14 void add(int i,int q,int p){
15     if(p<x||q>x) return;
16     if(q==p){
17         f[i]=y;a[x]=y; 
18         return;
19     }
20     int m=(q+p)/2;
21     add(2*i,q,m);
22     add(2*i+1,m+1,p);
23     f[i]=max(f[2*i],f[2*i+1]);
24 }
25 void ans(int i,int q,int p){
26     if(p<x||q>y) return;
27     if(q>=x&&p<=y){
28         maxn=max(maxn,f[i]);
29         return;
30     }
31     int m=(q+p)/2;
32     ans(2*i,q,m);
33     ans(2*i+1,m+1,p);
34 }
35 int main(){
36     scanf("%d",&n);
37     for(int i=1;i<=n;i++)
38         scanf("%d",&a[i]);
39     bt(1,1,n);
40     scanf("%d",&m);
41     for(int i=1;i<=m;i++){
42         scanf("%d%d%d",&d,&x,&y);
43         if(d==1) add(1,1,n);
44         else{
45             maxn=-2147483647;
46             ans(1,1,n);
47             printf("%d\n",maxn);
48         }
49     }
50 }
View Code

T2:【线段树】最大值(新版)

在N(1<=N<=100000)个数A1…An组成的序列上进行M(1<=M<=100000)次操作,操作有两种:
(1)1 L R C:表示把A[L]到A[R]增加C(C的绝对值不超过10000);
(2)2 L R:询问A[L]到A[R]之间的最大值。
输入
第一行输入N(1<=N<=100000),表示序列的长度,接下来N行输入原始序列;接下来一行输入M(1<=M<=100000)表示操作的次数,接下来M行,每行为1 L R C或2 L R
输出
对于每个操作(2)输出对应的答案。
这一道题跟T1差不多
注意区间修改的时候要用lazy  tag(用完清零)
上~代~码~
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,a[100010],m,f[400010],d,x,y,r,maxn,lazy[400010];
 4 void down(int i){
 5     if(lazy[i]){
 6         lazy[2*i]+=lazy[i];
 7         lazy[2*i+1]+=lazy[i];
 8         f[2*i]+=lazy[i];
 9         f[2*i+1]+=lazy[i];
10         lazy[i]=0;
11     }
12 }
13 void bt(int i,int x,int y){
14     if(x==y){
15         f[i]=a[x];
16         return;
17     }
18     int m=(x+y)/2;
19     bt(2*i,x,m);
20     bt(2*i+1,m+1,y);
21     f[i]=max(f[2*i],f[2*i+1]);
22 }
23 void add(int i,int q,int p){
24     if(p<x||q>y) return;
25     if(q>=x&&p<=y){
26         f[i]+=r;lazy[i]+=r;
27         return;
28     }
29     down(i);
30     int m=(q+p)/2;
31     add(2*i,q,m);
32     add(2*i+1,m+1,p);
33     f[i]=max(f[2*i],f[2*i+1]);
34 }
35 void ans(int i,int q,int p){
36     if(p<x||q>y) return;
37     if(q>=x&&p<=y){
38         maxn=max(maxn,f[i]);
39         return;
40     }
41     down(i);
42     int m=(q+p)/2;
43     ans(2*i,q,m);
44     ans(2*i+1,m+1,p);
45 }
46 int main(){
47     scanf("%d",&n);
48     for(int i=1;i<=n;i++)
49         scanf("%d",&a[i]);
50     bt(1,1,n);
51     scanf("%d",&m);
52     for(int i=1;i<=m;i++){
53         scanf("%d%d%d",&d,&x,&y);
54         if(d==1){
55             scanf("%d",&r);
56             add(1,1,n);
57         }
58         else{
59             maxn=-2147483647;
60             ans(1,1,n);
61             printf("%d\n",maxn);
62         }
63     }
64 }
View Code

T3:【RMQ】飞船

2008年9月25日21点10分,酒泉卫星发射中心指控大厅里,随着指挥员一声令下,长征二号F型火箭在夜空下点火起飞,神舟七号飞船载着翟志刚、刘伯明、景海鹏3位航天员,在戈壁茫茫的深邃夜空中飞向太空,开始人类漫步太空之旅。第583秒,火箭以7.5公里/秒的速度,将飞船送到近地点200公里、远地点350公里的椭圆轨道入口。而此时,火箭的燃料也消耗殆尽,即将以悲壮的方式与飞船告别。这个过程,在短短不到10分钟时间内,翟志刚和他的两名战友体会到了从超重到失重的过程。
除了超重和失重的感觉之外,就是浩瀚的长空中璀璨的星星,和地面上看到的星星不同,在太空中看到的星星是成一条直线的,一共有N(1<=N<=100,000)颗星星,编号为1到N,每个星星有自己的体积,由于在飞船中很无聊,除了不停地玩弄手中失重的书和笔之外没有别的事可干,此时翟志刚说我们来玩游戏吧,一共玩了M轮(1<=M<=100,000),每一轮都是给出两个整数L和R(1<=L<=R<=N),询问第L到第R颗星星之间最大星星的体积,每次答对的人就可以多休息一段时间。
由于翟志刚还要进行太空漫步,所以他现在请你帮忙,你得到的回报就是太空饼干。
输入
第一行输入N,M
接下来一行N个整数,表示星星的体积(1<=体积<=maxlongint)
接下来M行,每行两个整数L_i,R_i,表示询问区间。
输出
输出M行,每一行表示询问区间L_i到R_i之间最大星星的体积。
这也是道st表的板子题(不过线段树也能AC)
把两种代码都写上来吧
上~代~码~
st表:
 1 #include<cstdio>
 2 #include<cmath>
 3 #define max(a,b) (a>b?a:b)
 4 int n,m,x,l,r,t,a[100005],f[100005][21];
 5 int main(){
 6     scanf("%d%d",&n,&m);
 7     for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i][0]=a[i];
 8     for(int j=1;j<=log2(n);j++)
 9         for(int i=1;i<=n-(1<<j)+1;i++)
10             f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
11     for(int i=1;i<=m;i++){
12         scanf("%d%d",&l,&r);
13         t=log2(r-l+1);
14         printf("%d\n",max(f[l][t],f[r+1-(1<<t)][t]));
15     }
16 }
View Code

线段树:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,a[1000010],m,f[4000010],d,x,y,maxn;
 4 void bt(int i,int x,int y){
 5     if(x==y){
 6         f[i]=a[x];
 7         return;
 8     }
 9     int m=(x+y)/2;
10     bt(2*i,x,m);
11     bt(2*i+1,m+1,y);
12     f[i]=max(f[2*i],f[2*i+1]);
13 }
14 void ans(int i,int q,int p){
15     if(p<x||q>y) return;
16     if(q>=x&&p<=y){
17         maxn=max(maxn,f[i]);
18         return;
19     }
20     int m=(q+p)/2;
21     ans(2*i,q,m);
22     ans(2*i+1,m+1,p);
23 }
24 int main(){
25     scanf("%d%d",&n,&m);
26     for(int i=1;i<=n;i++)
27         scanf("%d",&a[i]);
28     bt(1,1,n);
29     for(int i=1;i<=m;i++){
30         scanf("%d%d",&x,&y);
31         maxn=-2147483647;
32         ans(1,1,n);
33         printf("%d\n",maxn);
34     }
35 }
View Code

最后

  这三道题十分简单,就是板子题,不过需要注意细节(所以这就是你做了两天的原因?)!

  至于后面的五道题,等我想(hui)打的时候再发吧!!!

  哦,如果想看后面的题请点这里

posted @ 2021-07-12 20:10  玻尔为了量子力学  阅读(150)  评论(0)    收藏  举报