#include <cstdio>
#include <initializer_list>
#include <iostream>
#include<algorithm>
using namespace std;
const int N=5e5+10;
const int LOGN=20;
int fmin[N][LOGN];//第几个数 包含的2的几次方
int fmax[N][LOGN];
int log[N];//储存log2
int a[N];
void inti(int n){
log[1]=0;
for(int i=2;i<=n;i++)log[i]=log[i/2]+1;
for(int i=1;i<=n;i++){
fmin[i][0]=a[i];
fmax[i][0]=a[i];
}
for(int j=1;j<=log[n];j++){
for(int i=1;i + (1<<j)-1 <=n;i++){//已知起点求终点 找这一块的尾
fmin[i][j]=min(fmin[i][j-1],fmin[i+(1<<(j-1))][j-1]);
fmax[i][j]=max(fmax[i][j-1],fmax[i+(1<<(j-1))][j-1]);//状态的偏移 找下一块的头 从左边状态转移到右边状态
}
}
}
int query(int l,int r,int op){
int k=log[r-l+1];
if(op==1)return min(fmin[l][k],fmin[r-(1<<k)+1][k]);//已知终点求起点
else return max(fmax[l][k],fmax[r-(1<<k)+1][k]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
inti(n);
while(q--){
int op,l,r;
cin>>op>>l>>r;
cout<<query(l,r,op)<<"\n";
}
return 0;
}
用st表 倍增的思想 把一个大的区间分成两半去求
在比较大小时 我们只要做到不漏即可 不必要求不重

京公网安备 11010502036488号