对于RMQ(Range Minimum Query)问题.给出一个n个元素的数组, {a1,a2,,,ai,,,an} ,对于查询操作Query(L,R),给出其中的 min{a1,a2,...,ai,...,an} ,
这里用一个简单的数据结构来解决这个问题,他的预处理只需要 O(n) ,对于查询只需要 O(1) .
di,j 表示从 i 开始,长度为 2j 的区间中的最小值,显然 di,j=min{di,j−1,di+2j−1,j−1}
void RMQ_init(const int *A,int n)
{
for(int i=0 ; i0] = A[i];
for(int j = 1 ; (1<for(int i =0 ; i+(1<1min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int RMQ(int L,int R)
{
int k =0 ;
if(Rreturn 0;
while(1<<(k+1)<=R-L+1)k++;
return min(d[L][k],d[R-(1<1][k]);
}
Uva 11235
这个题可以预处理每一个数字的次数cnt[i]表示第i段的次数,这里的 i 表示的是按照每个不同数字分的段,并且记录下每一个数的起始编号和结束编号,
对于每一个段[L,R]来说,if ele[L].v = ele[R].v,则Query(L,R) = R-L+1,否则,query(L,R) = max{ele[L]出现的个数,ele[R]出现的个数,RMQ(ele[L]的后一段,ele[R]的前一段)}
给出主代码
int solve(int L,int R)
{
int v;
if(ele[L].v !=ele[R].v)
{
v = max(ele[L].right-L+1,R-ele[R].left+1);
}else{
return R-L+1;
}
int ans = RMQ(ele[L].num+1,ele[R].num-1);
return max(ans,v);
}
int main()
{
//freopen("H:\\c++\\file\\stdin.txt","r",stdin);
while(scanf("%d",&n) && n)
{
scanf("%d",&q);
for(int i=0 ; i"%d",&ele[i].v);
}
int top = 0;
memset(cnt,0,sizeof(cnt));
value[0] = ele[0].v;
cnt[top]++;
ele[0].left = 0;
ele[0].num = 0;
for(int i=1 ; iif(ele[i].v>value[top])
{
value[(++top)] = ele[i].v;
ele[i].left = i;
}else
{
ele[i].left = ele[i-1].left;
}
cnt[top]++;
ele[i].num = top;
}
for(int i=0 ; i1;
RMQ_init(cnt,top+1);
int L,R;
while(q--)
{
scanf("%d %d",&L,&R);
int ans = solve(L-1,R-1);
printf("%d\n",ans);
}
}
return 0;
}