ST表与RMQ(倍增表)

【概述】

RMQ : Range Maximum/minimum Query   这就是指区间最大或最小值(区间最值)

ST表:Spars Table,一种可以解决 RMQ 的,基于倍增的数据结构,利用 ST 算法预处理打出的表,称为 ST 表。

ST 算法:对于 RMQ 问题,给出 n 个数 m 次询问,每次询问区间最值,当 m 较小时,使用暴力即可解决,但随着 m 的增大,O(logn) 的的询问处理已经不够,需要 O(1) 的询问。而 ST 算法可以在 O(nlogn) 时间内进行预处理,然后在 O(1) 时间内回答每个查询,其实际上就是一种动态规划与打表的思想,缺点是不支持修改操作。

一、原理

       要在 O(1) 求出区间的最值,一个很自然的想法是用动态规划处理的方法,用 dp[i][j] 来记录从i 个数开始,长度为j的区间的最大值,这样显然有状态转移方程:dp[i][j]=max(dp[i][j-1],a[i+j-1])。

dp[][]12345678910
15577121212121215
237712 1212121215 
377121212121215  
42121212121215   
5121212121215   
6166815     
766815      
84815       
9815        
1015         

        但这样预处理是 O(n*n) 的,所以还要进一步的优化。

        1、预处理(创建ST表)

        max 函数满足一个性质:允许区间重叠,即 max(i,j)=max( max(i,k) , max(k,j) ),也就是说,可以由两个较小的有重叠的区间,直接推出一个大区间,从而减少维护的区间数量。

例如:有数组A 为:5 3 7 2 12 1 6 4 8 15   则下表为该数组的ST表

F[ ][ ]2^0=12^1=22^2=42^3=8
155712
2371212
3771215
421212 
5121212 
6168 
76615 
848  
9815  
1015   

       DP的状态:采用倍增的思想,假设是要求数组A[i]的区间最值,F[i,j] 表示从第 i 个数起连续 2^j 个数中的最大值。

       F[1][0] 表示第 1 个数起,长度为 2^0=1 的最大值,其实就是 5。

       F[1][1] = max(5,3) = 5  表示第 1 个数起,长度为 2^1=2 的最大值,其实就是 5。

       F[1][2] = max(5,3,7,2) = 7  表示第 1 个数起,长度为 2^2=4 的最大值,其实就是 7。

       F[1][3] = max(5,3,7,2,12,1,6,4)=12表示第 1 个数起,长度为 2^3=8 的最大值,其实就是 12。

       F[2][2] = max(3,7,2,12)=12表示第 2 个数起,长度为 2^2=4 的最大值,其实就是 12。

       DP的初始值: 可以看出 F[i,0] = A[i]

       状态转移方程: 把 F[i][j] 平均分成两段 ( F[i][j] 一定是偶数个数字),从 i 到 i+2^(j-1)-1 为一段,i+2^(j-1) 到 i+2^j-1 为一段,长度均为 2^(j-1)。

       于是得到F[i][j] = max( F[i] [ j-1] , F[i+2^(j-1) ] [j-1] )

        F[3][2]=max(F[3][1],F[5][1])表示从第3个数起,长度为 2^2=4 的最大值,也就是长度为4的最大值,可以由前一列长度为2的两个最大值比较得出。

void ST_create()
{	for(int i = 1;i<=n;i++)F[i][0] = a[i];
	int k=log2(n);  //k=log(n)/log(2)
	for(int j = 1;j<=k;j++)
    {	for(int i = 1;i<=n-(1<<j)+1;i++)
        	F[i][j] = max(F[i][j-1],F[i+(1<<(j-1))][j-1]);	//前一列是跨多少长度,第二个数的行坐标就跨多少行	
	}
}
      2、查询

      假设要查询的区间为 (L,R),那么需要找到覆盖这个闭区间 [L,R] 的最小幂。

      由于区间长度为 R-L+1,因此可以取 s=log2(R-L+1),

      则有:RMQ(L, R) = max{ F[L][s] , F[ R-2^s+1][s] }

      例:要求区间 [1,5] 的最大值

      则有:s= log2(5-1+1) = 2

      则:RMQ(1,5) = max( F[1][2] , F[5-2^2+1][ 2]) = max(F[1][2] , F[2][2])

void ST_query(int l,int r)//求区间[l..r]的最值 
{	int s=log2(r-l+1);
    return  max(F[l][s],F[r-(1<<s)+1)][s]);	//取两个区间最值 
}

练习题:

模板题:洛谷P3865 【模板】ST 表

P2880 [USACO07JAN] Balanced Lineup G

P8818 [CSP-S 2022] 策略游戏

P7809 [JRKSJ R2] 01 序列

P7972 [KSN2021] Self Permutation

P7167 [eJOI2020 Day1] Fountain

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值