洛谷P3865 -【模板】ST表 - RMQ模板题 - ST算法
题目链接
https://www.luogu.com.cn/problem/P3865
适用范围
主要是处理区间最值问题。
时间复杂度
\(O(n\log_{}{n})\)的时间内进行预处理,\(O(1)\)的时间进行查询。(线段树解决可能会超时)
\(j\)即列数:最大是$\log_{2}{n} $(计算机上默认以log以2为底),
也就是如果以一个表格形式呈现的话,那么行数为\(n\),列数为$ \log_{2}{n} $。
本题的f数组列数开17就行,因为\(\log_{2}{1e5} \approx 16.6\)。
算法分析
ST算法是在线处理RMQ的算法,是一个DP思想,但是状态转移方程是从前面已知的一列转移过来,和背包有所不同。
主要思想就是:分治、倍增、动规。
\(f[i,j]\)数组表示的是:从第\(i\)个数起连续\(2^j\)个数中的最大值。(个数包括第\(i\)个数)
学习链接
https://www.bilibili.com/video/BV1pE411u7Gq?from=search&seid=10536624648902837005
注意
本题scanf输入会有一组数据TLE,所以建议快读。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+20;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int f[N][21];
int main()
{
int n=read(),m=read(); // 序列长度 询问次数
for(int i=1;i<=n;i++)
{
f[i][0]=read(); // 初始化f数组,画一个图可以得出这个结论
}
int x=(int)(log(n)/log(2));
for(int j=1;j<=x;j++)
{
int w=n-(1<<j)+1;
for(int i=1;i<=w;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
int w=(int)(log(r-l+1)/log(2));
printf("%d\n",max(f[l][w],f[r-(1<<w)+1][w])); // 别忘了+1
}
return 0;
}