定义及思路
用来解决RMQ问题,即查询区间内的最大值或者最小值,以下以最大值举例
用于解决可重复贡献问题的数据结构,需满足x pot x=x,如max(x,x)=x
时间复杂度:预处理o(nlogn),查询o(1)
讲解前定义:
st[i][j]表示[i,i+2j)区间内的最大值(最小值)
思路:
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1])
初始化
void pre(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
}
查询
如果我们有一个区间[1,5],那么我们的j要取什么呢,由数学知识可得,j取log 2 5,但是这样会漏掉最后一个数字,可以从前面开始求一次st[i][j],再从后面求一次st[i][j],二者取最大值即为区间最大值
int query(int l,int r)
{
int k = log2(r - l + 1);//这里需要换底公式计算,math库中log只能计算以e和10为底的对数
return max(st[l][k], st[r - (1 << k) + 1][k]);
}
完整代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m;
namespace ST{
int st[maxn][22];
void pre(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
}
int query_max(int l,int r){
int k=log2(r-l+1);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
}
using namespace ST;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&st[i][0]);
pre();
for(int i=1,l,r;i<=m;i++)scanf("%d%d",&l,&r),printf("%d\n",query_max(l,r));
return 0;
}