相关链接:
ST: Sparse Table
RMQ:RMQ
RMQ的两种实现方式:
一、线段树
二、稀疏表(ST)
平均时间复杂度:O(N*LogN)
如果不进行修改操作的话,ST的效率会更高。
ST的计算步骤:
一、DP计算ST
二、以O(1)查询(L,R)的最值
code:
int a[maxn],dp[maxn][30],n;//之前有笔误,dp的列数最多只有log2(maxn),在这里,我就写成30
//建立稀疏表
void st(int n)
{
for(int i=1;i<=n;++i)
dp[i][0]=a[i];
for(int j=1;(1<<j)<=n;++j) //之前的笔误,实际上是要保证i+2^j-1<=n还要保证2^j<=n
for(int i=1;i+(1<<j)-1;++i)
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//状态转移方程,注意优先级的问题,1+(j-1)要加上括号,否则会莫名其妙地出现问题
}
//O(1)的查询操作
int rmq(int l,int r)
{
int k=0;
while(1<<(k+1)<=(r-l+1)) k++;
return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
一些解释:
1.dp[i][j]的定义 ,
2.a[i]表示原数列。
2.状态转移方程为什么是这样?
3.对于<2>的解释:
4.到这里,聪明的读者一定已经完全掌握了DP计算ST;
5.现在,我们来看我们的查询函数RMQ为什么是这样子的:
首先,让我们假设我们要查询的区间是(L,R),
所以,区间的长度就是:,但是根据我们构造的ST,可能没有一个区间是对应我们要查询的区间的。
也就说:
因此,我们就要把要查询的区间分成两个部分:
而且,这两个部分的长度都必须是可以直接查询的。
接下来,我们该如何计算 : 呢?
易得:
同理:
所以令:
举个例子:
原数列:{1,2,3,4,5}
现在要查询:的最大值
之后我们比较大小: