题目申明:
本题是洛谷的P3865号题目,题目传送门:P3865 【模板】ST 表 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3865
简介:
ST表是离线算法
注:离线的意思是查找区间内的数值不会改变,如果会改变的话,称为在线,如果用ST表来解在线的题目的话,时间复杂度可能达不到要求。)
思路:
使用二维dp达成目地
dp方法:
dp[i][j]---表示从i位置开始(个数)为2^j区间的最值
dp[L_i][ L_j]=max_L
dp[R_i][R_j]=max_R
dp[L_i][R_j]=max(dp[L_i][L_j], dp[R_i][R_j])
由此得出dp公式:
dp[i][j]=max(dp[i][j-1],dp[i+2^(j-1)][j-1])
也可以这么写:
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1])
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
//预处理,时间复杂度为O(nlogn)
int n,m;
cin>>n>>m;
vector<vector<int>> dp(n+1,vector<int>(20));
vector<int> log2(n+1,-1);
for(int i=1;i<=n;i++){
scanf("%d",&dp[i][0]);//从i到(个数)2^0=1,也就是长度是1,这个区间里只有一个数,最大的数就是他自己
}
for(int i=1;i<=n;i++){
log2[i]=log2[i>>1]+1;//手动实现log
}
//j之所以放在前面是因为dp的高维(dp的第二个"[]")还没计算出来
for(int j=1;(1<<j)<=n;j++){//(1<<j)<=n是判断循环里最大的j是否大于n
for(int i=1;i+(1<<(j))-1<=n;i++){
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//联系图1,i+(1<<(j-1))是R_i的意思
}
}
//得出查找max时间复杂度为O(1)的结果
int l,r;
for(int i=0;i<m;i++){
scanf("%d%d",&l,&r);
int k=log2[r-l+1];
printf("%d\n",max(dp[l][k],dp[r-(1<<k)+1][k]));
}
return 0;
}