用来查询区间最值(区间和,差等要处理重复部分)
下面均以以最大值为例
初始化 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⌋ (下取整)
代码:
(感谢XLightGod(THU巨佬)指正我的错误,第12行下标范围是i+(1<<k)-1<=n)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 6 int a[10010],st[10010][21],n;//st的第二维取到log2(10010)即可 7 8 void init(){ 9 for(int i=0;i<=n;i++) 10 st[i][0]=i; 11 for(int k=1;(1<<k)<=n;k++) 12 for(int i=1;i+(1<<k)-1<=n;i++) 13 st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]); 14 15 } 16 17 int ask(int l,int r){ 18 int len=r-l+1; 19 int p=(int)log((double)(len))/log(2.0);//满足2^p<=r-l+1的最大p 20 return max(st[l][p],st[r-(1<<p)+1][p]); 21 } 22 23 //以最大值为例 24 int main(){ 25 scanf("%d",&n); 26 for(int i=1;i<=n;i++) 27 scanf("%d",&a[i]); 28 init(); 29 while(1){ 30 int l,r; 31 scanf("%d",&l); 32 if(l==-1)exit(0); 33 scanf("%d",&r); 34 int ans=ask(l,r); 35 printf("%d\n",ans); 36 } 37 return 0; 38 }