倍增RMQ演算法淺談
阿新 • • 發佈:2018-12-23
題目:
求某一區間的最大值。
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 }