[OI学习笔记]st表
用来查询区间最值(区间和,差等要处理重复部分)
下面均以以最大值为例
初始化 0(nlogn)
设st[i][k]为下标i开始的2k个元素的最值
则: st[i][k]=max{st[i][k-1],st[i+2k-1][k-1]}
即区间[i,i+2k -1]的前一半和后一半的最值取最大
查询 O(1)
对于区间[l,r],区间长度len=r-l+1;找到满足2p <=len的最大p
最大值ans=max{st[l][p],st[r-2p +1][p]}
显然,当2p !=len时,区间[l,l+p-1]和[r-2p +1][r]有重叠
这也是为什么前面说区间和,差等要处理重复部分。
2p <=len的p的最大值p <=log2len
则p=⌊log2len⌋ (下取整)
代码:
(注意第12行下标范围是i+(1<<k)-1<=n)
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> using namespace std; int st[100010][21],n;//st的第二维取到log2(10010)即可 void init(){ for(int k=1;(1<<k)<=n;k++) for(int i=1;i+(1<<k)-1<=n;i++) st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]); } int ask(int l,int r){ int len=r-l+1; //int p=(int)log((double)(len))/log(2.0);//满足2^p<=r-l+1的最大p int p=log2(len); return max(st[l][p],st[r-(1<<p)+1][p]); } //以最大值为例 int main(){ int m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&st[i][0]); init(); for(int i=1;i<=m;i++){ int l,r; scanf("%d%d",&l,&r); int ans=ask(l,r); printf("%d\n",ans); } return 0; }
本篇文章为SHINE_GEEK原创,转载请注明来源!
-------------------------------------
签名:自己选的路,跪着也要走完;理想的实现,需要不懈奋斗!
-------------------------------------
written_by:SHINE_GEEK
blog_addr:www.cnblogs.com/sjrb
-------------------------------------
签名:自己选的路,跪着也要走完;理想的实现,需要不懈奋斗!
-------------------------------------