首页 > 编程知识 正文

ST基础介绍,st的概念

时间:2023-05-06 12:00:07 阅读:184031 作者:521

世界真的很大

说来惭愧,直到昨天才搞清楚这个st表,然后花时间整理了一下思路,终于是差不多了。其实本来不想写的,网上看来看去好像st表除了RMQ,LCA就没什么了,况且LCA我会树链剖分,RMQ能写线段树,除了代码量少的那么一点点优势,我学他干嘛?后来一想,这种倍增的思想其实可能有点用,有可能在许多dp方程之类的能用得到,况且整体思想还很简单,就直接简单说明一下了。
以RMQ为例吧,介绍一下ST表。(这里就只管区间最大值了)
首先来见识一下ST表的核心数组st[i][j],意思是,由数列i位置往后推2^j个单位长度的区间里的最大值,然后呢,stmax的更新也就是dp的思想,st[i][j]可以由st[i][j-1],st[i+(1<<(j-1))][j-1]得到,因为2^(j-1)肯定是2^j的一半,相当于就是把一个区间的前后两部分的最大值相比较,得出这个区间的最大值,这是一个递推的关系。代码:

for(int j=1;j<=log[n];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]);

查询的时候便更简单,有了这个st表几乎无所不能,没错,o(1)查询。
记录查询区间为l,r。如果(r-l+1)正好是2^j,那么就直接返回st[l][j]就行了。但不可能每次查询的时候正好区间长度就是2的整数次幂,所以我们直接取区间长度的log值,向下取整,有可能并不能完全覆盖区间长度,但也绝对比区间的一半要长,(理解一下log),那么我们就可以把区间分成两个部分,长度都是2^(log(n)),因为只是取最值,所以两段可以重合一部分,代码:

int query(int l,int r){ int k=log[r-l+1]; return max(st[l][k],st[r-(1<<k)+1][k]);}

这里是提前预处理了log值,从1到n,向下取整,log函数的预处理其实可以和st表的预处理结合到一起,好好理解下:

for(int i=1;i<=n;i++) { log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1]; st[i][0]=a[i]; }

这个log就是重点了。
完整代码:

#include<stdio.h>#include<algorithm>using namespace std;int n=100,m,a[10010],st[10010][40],log[10010];void init(){ log[0]=-1; for(int i=1;i<=n;i++) { log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1]; st[i][0]=a[i]; } for(int j=1;j<=log[n];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]);}

嗯,就是这样。。。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。