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)输出对应的答案。
这是一道很明显的板子题
注意细节就行了
上~代~码~
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 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 }
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差不多
这一道题跟T1差不多
注意区间修改的时候要用lazy tag(用完清零)
上~代~码~
View Code
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 }
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表的板子题(不过线段树也能AC)
把两种代码都写上来吧
上~代~码~
st表:
View Code
View Code
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 }
线段树:
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 }
最后
这三道题十分简单,就是板子题,不过需要注意细节(所以这就是你做了两天的原因?)!
至于后面的五道题,等我想(hui)打的时候再发吧!!!
哦,如果想看后面的题请点这里

浙公网安备 33010602011771号