ST算法
ST算法可以在 \(O(N \log N)\) 时间的预处理后,以 \(O(1)\) 的时间复杂度在线回答区间最值问题。
状态转移
一个序列的子区间个数显然有 \(N^2\) 个,根据倍增思想,我们可以在这个空间里选择一些 \(2\) 的整数次幂的位置作为代表值。
状态:\(f[i][j]\) :数组 \(a\) 在子区间 \([i, i+2^j-1]\) 中的最大值
初值:显然 \(f[i][0] = a[i]\),即 \(a\) 在子区间 \([i, i]\) 中的最大值
状态转移:\(f[i][j] = max(f[i][j-1],f[i+2^{j-1}][j-1])\)
Example:
假设现有一数组 \(a = \{ 5,3,7,9,6,4,1,2\}\),可以得到如下表格
\(i\) | \(a\) | \(ST[i][0]\) | \(ST[i][1]\) | \(ST[i][2]\) | \(ST[i][3]\) |
---|---|---|---|---|---|
\(1\) | \(5\) | \(5\) | \(5\) | \(9\) | \(9\) |
\(2\) | \(3\) | \(3\) | \(7\) | \(9\) | \ |
\(3\) | \(7\) | \(7\) | \(9\) | \(9\) | \ |
\(4\) | \(9\) | \(9\) | \(9\) | \(9\) | \ |
\(5\) | \(6\) | \(6\) | \(6\) | \(6\) | \ |
\(6\) | \(4\) | \(4\) | \(4\) | \ | \ |
\(7\) | \(1\) | \(1\) | \(2\) | \ | \ |
\(8\) | \(2\) | \(2\) | \ | \ | \ |
若想求出 \(ST[1][2]\) 的值,即区间 \([1,4]\) 中的最值
我们可以取 \(ST[1][1]\) 和 \(ST[3][1]\) 的最大值作为 \(ST[1][2]\) 的值
因为 \(ST[1][1]\) 代表区间 \([1,2]\) 中的最大值,\(ST[3][1]\) 代表区间 \([3,4]\) 中的最大值
取两个数的最大值,即为区间 \([1,4]\) 中的最值
由此可得状态转移方程:\(f[i][j] = max(f[i][j-1],f[i+2^{j-1}][j-1])\)
照应上述例子,\(3 = 1 + 2^{2-1}\),恰好满足。
初始化
根据状态转移方程,可得如下代码:
void ST_pre()
{
for(int i=1;i<=n;i++)
ST[i][0]=a[i];
int t=log2(n)+1;
for(int j=1;j<=t;j++)
for(int i=1;i<=n-(i<<j)+1;i++)
ST[i][j]=max(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
查询
当询问区间 \([l,r]\) 中的最值时,令区间长度 \(x = r-l+1\)
我们可以先计算出一个\(k\),满足 \(2^k \leq x \leq 2^{k+1}\)
即将区间分为 比 \(x\) 小的 \(2\) 的最大整数幂 和 剩下的部分
再将剩下的部分进行分解,直到不能再分为止
然后依次返回每个区间的最值,取最大值即可
int ST_query(int l,int r)
{
int k=log2(r-l+1);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
标签:int,max,最大值,ST,算法,区间,最值
From: https://www.cnblogs.com/LanSky6/p/16823171.html