st表是解决区间RMQ(区间最值问题)的一类算法,时间复杂度为O(nlogn)的预处理和O(1)的查询,其主要运用了类似倍增的思想...
总体来说,st表的用处还是挺大的,代码也比较短,容易记...
st表
若现在给定一个长度为n的序列A,每次给定两个数l,r,求出A[l]~A[r]中的最大值...
那么我们考虑怎么做,首先是朴素做法,每次询问最大值时用for循环从l到r跑一遍,每次循环复杂度为O(r - l)
那有没有一种算法可以让我们以O(1)的复杂度就知道最大值呢?
这时我们引进st表算法...
具体做法:
我们定义一个二维数组st[i][j]表示区间[i,i+2^j-1]里的最大值,那么有st[i][0] = A[i],即A[i]是区间[i,i]的最大值,然后我们运用倍增的思想,每次维护区间最值就行了,预处理的代码如下:
inline void init() { for(int i = 1;i <= n;i ++) st[i][0] = a[i]; for(int j = 1;j <= 21;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]); }
关于查询,我们需要先对查询区间的长度取一个对数k,那么2^k一定大于等于区间长度的一半,接着我们从左右两个端点处向内取最大值(即使有重叠也没事),这样我们就O(1)的查询出了区间的最大值,代码如下:
inline int query(int l,int r) { int k = log(r - l + 1); return max(st[l][k],st[r - (1<<k) + 1][k]); }
下面有一道板子题
代码如下:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> const int maxn = 1e5 + 5; int n,m; int st[maxn][23]; inline int read() { char ch = getchar();int x = 0,f = 1; while(ch<‘0‘||ch>‘9‘){if(ch == ‘-‘) f = -1; ch = getchar();} while(ch>=‘0‘&&ch<=‘9‘){x = x*10 + ch -‘0‘; ch = getchar();} return x*f; } inline void init() { for(int i = 1;i <= 21;i ++) for(int j = 1;j+(1<<i)-1 <= n;j ++) st[j][i] = std::max(st[j][i-1],st[j+(1<<(i-1))][i-1]); } inline int query(int l,int r) { int k = log2(r-l+1); return std::max(st[l][k],st[r-(1<<len)+1][k]); } int main(int argc, char const *argv[]) { n = read(); m = read(); for(int i = 1;i <= n;i ++) st[i][0] = read(); init(); for(int i = 1;i <= m;i ++) { int l = read(); int r = read(); printf("%d\n",query(l,r)); } return 0; }
原文地址:https://www.cnblogs.com/Ackers/p/10010223.html
时间: 2024-10-03 20:14:01