数据结构1 倍增、ST表,RMQ

使用  倍增、ST表   解决区间最值的查询问题   RMQ 

1.倍增


任意整数均可表示成若干个2的次幂项的和.

5--》101

26--》11010

也就是说2的次幂可以拼接成任何一个需要的

 

倍增:成倍的增长,如果问题的状态空间特别大,一步一步的递推算法复杂度太高,可以通过倍增思想,只考察2的整数次幂位置,快速缩小求解范围,知道所要的解。

 

2.ST表


 

系数表Sparse Table算法采用倍增的思想,在O(NlogN)的时间构造一个二维表之后,可以在o(1)的时间在线查询区间[l,r]的最值。ST算法可以有效的解决在线RMQ问题

F[i,j]表示区间[i, i+2^j-1]的最值,区间长度为2^j

 

其实就是基于动态规划的思想 的 静态表方法

通过k=logn将🌲树表划分取值

1,2,3...k

 

 

 1 #include <iostream>
 2 #include <cmath>  // 使log函数
 3 /*
 4  cmath使用方法介绍:
 5  log():以e为底的对数,exp(5) = e^5    log(exp((5)) = 5
 6  log10():以10为底的对数
 7  log2():以2位底的对数
 8  任何一个对数logm(n) = log(n)/log(,)
 9  */
10 using namespace std;
11 
12 const int maxn = 105;
13 int n, a[maxn], F[maxn][maxn];  // F(i,j)表示区间[i, i+2^j-1]的最值,区间长度为2^j
14 
15 void ST_create(){
16     for(int i=1; i<=n; i++) // 初始化
17         F[i][0] = a[i];  //n-1
18         int k=log2(n);  // log(n)/log(2)   两种版本的问题
19     for(int j=1; j<=k; j++){
20         for(int i=1; i<=n-(1<<j)+1; i++){  // n-2^j+1:n-3、n-5、n-7
21             F[i][j] = max(F[i][j-1], F[i+(1<<(j-1))][j-1]);
22         }
23     }
24 }
25 
26 int ST_query(int l, int r){  // 求区间[l,r]的最值
27     int k=log(r-l+1);
28     return max(F[l][k], F[r-(1<<k)+1][k]);
29     // 取两个区间最值    F[l][k]:l往后数k个    F[r-(1<<k)+1][k]:r往前数k个
30 }
31 
32 void ST_print(){
33     // 按列填写的表
34     int k=log2(n);
35     for(int j=0; j<=k; j++){
36         for(int i=0; i<=n-(1<<j)+1; i++){  // n-2^j+1 打印第一列
37             cout << F[i][j] << " ";
38         }
39         cout << endl;
40     }
41 }
42 
43 int main(){
44     // 10 5 3 7 2 12 1 6 4 8 15
45     int l, r;
46     int i, v;
47     cin >> n;
48     for(i=1; i<=n; i++)
49         cin >> a[i];
50     ST_create();
51     ST_print();
52     cout << "输入查询最值的区间l r:" << endl;
53     cin >> l >> r;
54     cout << ST_query(l, r) << endl;
55     return 0;
56 }

 

 

POJ3264

http://poj.org/problem?id=3264

6 3
1
7
3
4
2
5
1 5
4 6
2 2
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 const int maxn = 50000+10;
 9 
10 int h[maxn];
11 int Fmax[maxn][20];
12 int Fmin[maxn][20];
13 int N, Q;
14 
15 void ST_create(){
16     for(int i=1; i<=N; i++){
17         Fmax[i][0] = Fmin[i][0] = h[i];
18     }
19     int k = log2(N);
20     for(int j=1; j<=k; j++){
21         for(int i=1; i<=N-(1<<j)+1; i++){
22             Fmax[i][j] = max(Fmax[i][j-1], Fmax[i+(1<<(j-1))][j-1]);
23             Fmin[i][j] = min(Fmin[i][j-1], Fmin[i+(1<<(j-1))][j-1]);
24         }
25     }
26 }
27 
28 int ST_query(int l, int r){
29     int k = log2(r-l+1);
30     return max(Fmax[l][k], Fmax[r-(1<<k)+1][k]) - min(Fmin[l][k], Fmin[r-(1<<k)+1][k]);
31     
32 }
33 
34 int main(){
35     // freopen("test.txt", "r", stdin);
36 //    cin >> N >> Q;
37 //    for(int i=1; i<=N; i++){
38 //        cin >> h[i];
39 //    }
40 //    ST_create();
41 //    int l, r;
42 //    for(int i=1; i<=Q; i++){
43 //        cin >> l >> r;
44 //        cout << ST_query(l, r) << endl;
45 //    }
46     int l, r;
47     while(~scanf("%d%d", &N, &Q)){
48         for(int i=1; i<=N; i++)
49             scanf("%d", &h[i]);
50         ST_create();
51         for(int i=1; i<=Q; i++){
52             scanf("%d%d", &l, &r);
53             printf("%d\n", ST_query(l, r));
54         }
55     }
56     return 0;
57 }

 

注意题目中测试用例可能会有多个

 

posted @ 2019-09-09 16:28  JCcodeblogs  阅读(355)  评论(0编辑  收藏  举报