用ST表求静态区间最大值
ST表不支持修改,预处理时间为nlog(n),但查询时间为O(1)
线段树支持修改,预处理时间为nlog(n),但查询时间是log(n)
ST详解:
用f[i][j]表示区间 j~j+2^i-1 的最大值(即从j开始,向后2^i次这个区间中的最值)
预处理出bin[i]表示2^i,log[i]就表示log2(i)
#include<bits/stdc++.h>
#define N 200010
using namespace std;
namespace program{
long long bin[30],log[N],a[N];
long long n,m,l,r,f[30][N];
template<class T>
T read(){
T s=0;
int ch;
while(!isdigit(ch=getchar()));
do
s=s*10+(ch^48);
while(isdigit(ch=getchar()));
return s;
}
inline void init(){
bin[0]=1;//2^0=1
for(int i=1;i<=20;i++)
bin[i]=bin[i-1]*2;//bin[i]是2^i
log[0]=-1;
for(int i=1;i<=100010;i++)
log[i]=log[i/2]+1;//比方说:log(2(32))=5=log(2(16))+1
for(int i=1;i<=n;i++)
f[0][i]=a[i];//预处理:从i开始只有一个那么无论最大最小都是它本身
}
inline void work(){
n=read<long long>();//n是数组长度
m=read<long long>();//m是询问次数
for(int i=1;i<=n;i++)
a[i]=read<long long>();
init();
for(int i=1;i<=log[n];i++)
for(int j=1;j<=n;j++)
if(j+bin[i]-1<=n)
f[i][j]=max(f[i-1][j],f[i-1][j+bin[i-1]]);
//i-1很巧妙的吧f[i][j]这段区间分成了大小相同的两段,头指针分别为j和j+bin[i-1]
while(m--){
l=read<long long>();
r=read<long long>();
long long oo=log[r-l+1];
cout<<max(f[oo][l],f[oo][r-bin[oo]+1])<<'\n';
//和上面很像,然而要稍微反一下要先求出log(2,(r-l+1))
}
}
}
int main(){
program::work();
return 0;
}