算法学习——st表

st表是一种基于倍增思想的DP。

用于求一个数列中的某个区间的最大/最小值。

用st[i][j]表示从第i个开始往后2^j个点,最大的是多少。

我们令k[i]表示2^i等于多少

那么有转移方程

st[i][j] = max(st[i][j - 1], st[i + k[i - 1]][j - 1]);

为什么呢?

例如这幅图,显然黑色块的答案可以由合并下面两块得到。

那如果查询的时候不是2的整次幂怎么办?

这其实是没有问题的,你可以观察下图……

因为小区间有重叠部分并不影响,因此完全可以用稍大一点的小区间凑出大区间。
预处理一点信息以快速查询答案即可。

(早期代码,没有空格空行,略丑)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,s[100500],f[100500][18],p[100500];
 4 int Max(int a,int b)
 5 {
 6     if(a>b)return a;
 7     else return b;
 8 }
 9 int Min(int a,int b)
10 {
11     if(a<b)return a;
12     else return b;
13 }
14 void pre()
15 {
16     int i,a,key=1;
17     for(i=1;i<=n;i++)
18     {
19         if(i==(key<<1))p[i]=p[i-1]+1,key<<=1;
20         else p[i]=p[i-1];
21         scanf("%d",&a);
22         f[i][0]=a;
23     }
24     for(int j=1;j<=17;j++)
25         for(i=1;i<=n;i++)
26         {
27             f[i][j]=Max(f[i][j-1],f[Min(i+(1<<(j-1)),n)][j-1]);
28         }    
29 }
30 int main()
31 {
32     int i,a,b,k;
33     scanf("%d%d",&n,&m);
34     pre();
35     for(i=1;i<=m;i++)
36     {
37         scanf("%d%d",&a,&b);
38         k=p[b-a+1];
39         printf("%d\n",Max(f[a][k],f[b-(1<<k)+1][k]));
40     }
41     return 0;
42 }

 

posted @ 2018-09-15 16:43  ww3113306  阅读(278)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。