题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2176
RMQ,就是范围最小值的缩写,这个算法是Tarjan 的 Sparse-Table 算法,复杂度为O(n*log(n)).
就是用数组d[i][j]表示范围[i,i+2^j-1]中的最小值。
然后有递推式
d[i][j] = min(d[i][j-1],d[i+2^(j-1)][j-1]).
有边界条件d[i][0] = A[i].
然后就能求出所有的d[i][j].查询时只需找出2^(k+1) <= R-L+1的最大的k值,取等号时,k要+1.
答案为min(d[L][k],d[R-(1<<k)+1][k]).这两个区间有重叠,木有关系的,不是吗?
本题用Sparse-Table算法,改成求最大值即可。具体解法采用游程编码。
如输入的数组为-1,-1,1,1,1,1,3,10,10,10.则能得到(-1,2),(1,4),(3,1),(10,3),(a,b)表示值为a的数有b个。
然后将数组分为4块,编号分别为1,2,3,4.用辅助数组num[i],left[i],right[i]记录位置i所在的块的编号,以及块的左端点和右端点位置。
数组 -1,-1,1,1,1,1,3,10,10,10.
num 1, 1,2,2,2,2,3,4, 4, 4.
left 1 , 1,3,3,3,3,7,8, 8, 8.
right 2, 2,6, 6,6,6,7,10,10,10
然后答案为max(right(L)-L+1 , R - left[R]+1, max (num[L]+ 1, num[R] - 1));
特判当L和R在同一段时答案是R-L+1.
当num[L]+1 > num[R]-1时,最大值为负无穷。
贴代码:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N =100005; 5 int c; 6 //元素从1编到n 7 int d[N][30],n,cnt[N],num[N],left[N],right[N]; 8 void RMQ_init() 9 { 10 for(int i=1; i<=c; ++i) d[i][0] = cnt[i]; 11 for(int j=1; (1<<j) <= c; ++j) 12 for(int i=1; i+j-1<=c; ++i) 13 d[i][j] = max(d[i][j-1],d[i+(1<<(j-1))][j-1]); 14 } 15 int RMQ(int L,int R) 16 { 17 if(L>R) return 0; 18 int k=0; 19 while((1<<(k+1)) <= R-L+1) ++k; 20 return max(d[L][k],d[R-(1<<k)+1][k]); 21 } 22 int main() 23 { 24 // freopen("in.txt","r",stdin); 25 int n,Q,a; 26 while(scanf("%d",&n),n) 27 { 28 for(int i=0; i<=n; ++i) cnt[i]=0; 29 scanf("%d%d",&Q,&a); 30 int p = a; 31 c=1,cnt[c] = 1,num[1] = c; 32 for(int i=2; i<=n; ++i) 33 { 34 scanf("%d",&a); 35 if(a != p) 36 { 37 p = a; 38 ++c; 39 } 40 ++cnt[c]; 41 num[i] = c; 42 } 43 int s =0; 44 for(int i=1; i<=c; ++i) 45 { 46 for(int j=1; j<=cnt[i]; ++j) 47 left[s+j] = s+1,right[s+j] = s+cnt[i]; 48 s += cnt[i]; 49 } 50 RMQ_init(); 51 while(Q--) 52 { 53 int l,r; 54 scanf("%d%d",&l,&r); 55 if(num[l] == num[r]) 56 { 57 printf("%d ",r-l+1); 58 continue; 59 } 60 int ans=right[l]-l+1; 61 if(r-left[r]+1 > ans) ans = r-left[r]+1; 62 int d = RMQ(num[l]+1,num[r]-1); 63 if(d > ans) ans =d; 64 printf("%d ",ans); 65 } 66 } 67 return 0; 68 }