首先用倍增法解決一道求區間最大值問題,算是倍增的入門了。
其實也算是一種dp,不過大家把這個二維dp數組叫做ST表。
ST表數組:f[i][j],表示區間【i,i+2j-1】的最大值。這個區間的大小是2j個數。
ST表的初始化:f[i][0]=a[i]。(顯然這是區間大小為1的時候)
ST表的遞推過程:
1,由區間大小為1的項轉移得到區間大小為21的項
2,由區間為21的項轉移得到區間為22的項
3,由區間為22的項轉移得到區間為23的項
。。。
這就是倍增的由來了吧。
這個遞推過程的代碼:
1 void RMQ(int N){ 2 for(int j=1;(1<<j)<=N;j++) 3 for(int i=1;i<=N;i++) 4 if(i+(1<<j)-1<=N) 5 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 6 }
經過處理后,訪問一段長區間便能利用事先處理好的數據得出答案
比如詢問最大值的一項處理技術:
因為區間的長度為j-i+1,所以可以取k=log2(j-i+1)。
則RMQ(A,i,j)=max(f[i][k],f[j-2^k+1][k])。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 using namespace std; 7 int a[100001],f[100001][20]; 8 9 void RMQ(int N){ 10 for(int j=1;(1<<j)<=N;j++) 11 for(int i=1;i<=N;i++) 12 if(i+(1<<j)-1<=N) 13 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 14 } 15 int main(){ 16 int N,M; 17 int tt; 18 cin>>tt; 19 while(tt--) 20 { 21 cin>>N; 22 for(int i=1;i<=N;i++) cin>>a[i]; 23 for(int i=1;i<=N;i++) f[i][0]=a[i]; 24 RMQ(N); 25 cin>>M; 26 while(M--){ 27 int l,r; 28 cin>>l>>r; 29 int k=(int)(log((double)(r-l+1))/log(2.0)); 30 printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k])); 31 } 32 } 33 return 0; 34 }