ST表的实现与简析

突然想写博客了,刚好把这两天学的东西巩固一下,看着自己半年前的作品真是触目惊心,代码品质极差,文章冗长又半天戳不到重点,不过还是留在那里做个警醒吧。

一、ST表的作用

用于以常数倍的速度查询某个区间的特定值,这个值的选取规则是要符合区间加法,例如最值。缺点在于它和差分数组一样,只支持离线的。

二、ST表的核心原理

设一数为 len , 我们知道对于任意个大于零的数都有:2 ^ log(2) len > len / 2 并且 2 ^ log(2) len <= len ,而这个特定数字 2^log(2)len 就是这个算法的核心,原因就是满足上述规则,我们后面就设为 k 。那么现在我们假定一个区间[L,R] ,这个区间的长度为 R -  L + 1 , 即 len = (R - L + 1),k = 2 ^ log(2)(R - L+1)。现在我们就问题创建两个新区间[L,L+K] [R-K,R],如图:

我们可以很形象的发现这两个区间的合并起来是直接包含整个区间的,若查找的特定值满足区间加法,则根据相应规则在两区间内做选择即可

三、ST表的实现方法

为了方便上述核心原理中的选择部分,所以我们给区间上的每一个点 x (1<= x <= len)后面2^log(2) k (x + 2 ^ log(2)k - 1<= len)区间做一个预处理,代码的算法利用dp实现,对于某个点 x 如图:

现设计这个dp数组 ,设dp[x][k] 为 x个点后的2 ^ k 区域内的一个特定值(后面为了方便理解,就以最小值为例),对于状态转移方程,我们知道每一个区域都是可以由两部分组成的(2 ^ k = 2 ^ (k-1) + 2 ^ (k-1)),而这个状态转移方程就可以很容易写出来:

                                                               \left\{\begin{matrix}DP[x][k] = min(DP[x][k-1],DP[x+2 \wedge (k-1)][k-1]) (k != 0) \\ DP[x][0] = A[i](1 <= i <= len) \end{matrix}\right.

四、实现代码:

void prest()
 {
    LOG[0] = -1;
    for(int i = 1 ; i <= n ; ++ i)
    {
       sta[i][0] = a[i];
       LOG[i] = ( ( i & (i-1) ) == 0) ? LOG[i-1] + 1 : LOG[i-1];
    }
    for(int i = 1 ; i <= LOG[n] ; ++ i)//每一个区间的大小的对数值
      for(int j = 1 ; j + (1 << i) - 1 <= n ; ++ j)//可能起点
         {
              sta[j][i] = min(sta[j][i-1],sta[j+(1 << (i-1))][i-1]);
         }//因为每一次状态转移时,前一次的区间值都会参与影响,所以我们以区间值作为外循环
 }
int querya(int l , int r)
{
  int pos = LOG[(r - l) + 1];//相应对数值
   return min(sta[l][pos],sta[r-(1<<pos)+1][pos]);//合并区间并选择
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值