倍增RMQ算法浅谈

题目:

求某一区间的最大值。

 

f[a][b]中a代表的是当前的位置,b代表的是以a为起点往后移动的区间长度2^b。

 1 void bz(int n)
 2 {
 3     for(int i=1;i<=n;i++)
 4         f[i][0]=a[i];//先定义长度1为自己本身。
 5     for(int j=1;(1<<j)<=n;j++)//以区间逐步移长。//tip1
 6     {
 7         for(int i=1;i+(1<<j)-1<=n;i++)//点的位置逐步往后移。//tip2
 8           f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
 9     }
10 }

其实tip1与tip2是利用以小的区间的最大值来逐步往上推更大的区间的最值。具体怎么推呢就需要利用到倍增思想(其实跟二分很相似)。

我们来模拟一下吧!

f[1][1]=max(f[1][0],f[2][0]);f[1][2]=max(f[1][1],f[3][1]);

f[1][1]={1,2},f[1][0]={1},f[2][0]={2},f[1][2]={1,2,3,4},f[3][1]={3,4};//大括号里面代表的是位置。

因此可以看出要求f[1][1]就直接看1位置与2位置的最值,f[1][2]是由f[1][1]与f[3][1]比较得出的。在这里也体现了由小区来推广到大区间,因为所求的大区间都可以通过二进制关系分为两个小区间问题(若重叠也是没关系的),而最小的问题也就是最初定义f[a][0]为a位置本身的问题;

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn=1e3+7;
 7 int num[maxn],f[1000][1000];
 8 int main()
 9 {
10     int n,a,b,c,d,q,l,r;
11     while(~scanf("%d",&n))
12     {
13         for(int i=1;i<=n;i++)
14         {
15             scanf("%d",&num[i]);
16         }
17         for(int i=1;i<=n;i++)
18         {
19             f[i][0]=num[i];
20         }
21         for(int i=1;i<20;i++)
22         {
23             for(int j=1;j+(1<<(i-1))-1<=n;j++)
24             {
25                 f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
26             }
27         }
28         cin>>q;
29         for(int i=1;i<=q;i++)
30         {
31             cin>>l>>r;
32             int k=(int)(log(r-l+1.0)/log(2.0));
33             printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));
34         }
35     }
36 }

 

posted @ 2018-12-23 21:59  To_Ashen  阅读(504)  评论(0编辑  收藏  举报