浅谈ST表
先丢个板子:
https://www.luogu.org/problemnew/show/P3865
基本思路:
ST表运用的是 倍增+动态规划 的思想,预处理的时间复杂度是O(nlogn),查询是O(1)的。
ST表的存储是用的二位数组st [ i ] [ j ] ,表示以第I位开头,长度为2^J的区间。
题目:给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大(小)值。
这里我们只谈最大值,因为最小值也是同样的道理,把函数Max改成Min就可以了。
具体实现:
输入:把长度为N的序列存到ST[ i ] [ 0 ] 中,因为以i开头长度为2^0就是i。
预处理:动态规划解决,st[ j ][ i ]=max(st[ j ][ i-1],st[ j+(1<<( i-1 ))] [i-1]);
当前区间最大值由两个子区间最大值得来。
输出:从两个重叠的子区间取最大值。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int n,stb[100005][22],m;//以I开头,长度为2^j的区间 void init() { for(register int i=1;i<=21;i++) for(register int j=1;(j+(1<<i)-1)<=n;j++) stb[j][i]=max(stb[j][i-1],stb[j+(1<<(i-1))][i-1]); } void query(int l,int r) { int k=log2(r-l+1); printf("%d ",max(stb[l][k],stb[r-(1<<k)+1][k])); } int main() { scanf("%d%d",&n,&m); for(register int i=1;i<=n;i++) scanf("%d",&stb[i][0]); init(); for(register int i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); query(l,r); } return 0; }
我比较懒,所以代码里注释极少...