【ST表(RMQ)】

ST表

  ST表是一种解决RMQ(区间最值问题)的强有力的工具

  它可以做到O(nlogn)预处理,O(1)查询最值。

实现

  ST表其实是一种倍增的思想,我们就拿取最大值为例:

开一个二维数组Max,其中Max[i][j]表示从第i位开始,包括第i位在内的2^j个数中最大的数,例如Max[i][1]表示第i个数和第i+1个数中大的那个数。

 

然后就类似于二分的样子,下一层也是拿两个已得到的区间的最大值作比较,然后存储。

预处理代码

1 for(int j=1;j<=21;j++)
2     {
3         for(int i=1;i+(1<<j)-1<=n;i++)
4         {
5             Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
6         }
7     }

  为什么要先循环j呢?因为我们是一层一层向上搜的,每一层的答案需要下面的基础,所以把j放在外层,然后(1<<(j-1))就是把二进制的1向左移动(j-1)位,也就是2^(j-1)。

查询  

  查询也比较简单,我们只需要求出k=log2(r-l+1)(求2的k次幂小于这一段区间的值,并且尽可能大),然后得到两个区间,比较就行了

 (图片来源)

然后取最大值返回就可以了

1 int ST(int l,int r)
2 {
3     int k=log2(r-l+1);
4     return max(Max[l][k],Max[r-(1<<k)+1][k]);
5 }

既然了解了这么多,不如.......(放心,都是模板题)

洛谷P3865 【模板】ST表

 1 #include<bits/stdc++.h>
 2 #define N 100005
 3 using namespace std;
 4 int n,m;
 5 int Max[N][21];
 6 int ST(int l,int r)
 7 {
 8     int k=log2(r-l+1);
 9     return max(Max[l][k],Max[r-(1<<k)+1][k]);
10 }
11 int main()
12 {
13     cin>>n>>m;
14     for(int i=1;i<=n;i++)
15     {
16         scanf("%d",&Max[i][0]);
17     }
18     for(int j=1;j<=21;j++)
19     {
20         for(int i=1;i+(1<<j)-1<=n;i++)
21         {
22             Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
23         }
24     }
25     int l,r;
26     for(int i=1;i<=m;i++)
27     {
28         scanf("%d%d",&l,&r);
29         printf("%d
",ST(l,r));
30     }
31     return 0;
32 }

洛谷P2251 质量检测

 1 // luogu-judger-enable-o2
 2 #include<bits/stdc++.h>
 3 #define N 100005
 4 using namespace std;
 5 int n,m;
 6 int Min[N][21];
 7 int ST(int l,int r)
 8 {
 9     int k=log2(r-l+1);
10     return min(Min[l][k],Min[r-(1<<k)+1][k]);
11 }
12 int main()
13 {
14     cin>>n>>m;
15     for(int i=1;i<=n;i++)
16     {
17         scanf("%d",&Min[i][0]);
18     }
19     for(int j=1;j<=21;j++)
20     {
21         for(int i=1;i+(1<<j)-1<=n;i++)
22         {
23             Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
24         }
25     }
26     for(int i=1;i+m-1<=n;i++)
27     {
28         printf("%d
",ST(i,i+m-1));
29     }
30     return 0;
31 }

洛谷P1816 忠诚

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int Min[100005][21];
 4 int n,m;
 5 int ST(int l,int r)
 6 {
 7     int k=log2(r-l+1);
 8     return min(Min[l][k],Min[r-(1<<k)+1][k]);
 9 }
10 int main()
11 {
12     cin>>n>>m;
13     for(int i=1;i<=n;i++)
14     {
15         scanf("%d",&Min[i][0]);
16     }
17     for(int j=1;j<=21;j++)
18     {
19         for(int i=1;i+(1<<j)-1<=n;i++)
20         {
21             Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
22         }
23     }
24     for(int i=1;i<=m;i++)
25     {
26         int l,r;
27         scanf("%d%d",&l,&r);
28         printf("%d ",ST(l,r));
29     }
30  } 
原文地址:https://www.cnblogs.com/hualian/p/11215613.html