poj3368 RMQ

题目大意说给出一系列数,这列数是不降的,然后任意给出一个区间[i,j],让你求出那个重复次数最多的数的出现次数。由于给出的查询次数很多,我就考虑用RMQ来解,但是这个不能直接套用模板,因为加入我们对区间[i,j]进行查询,如果从k处分开取两边区间的最大的重复次数是不一定正确的,因为分开的那个地方可能把实际重复次数最多的那个数一分为二,这样求出的就不是最大的了,所以只需要多加一个判断,从分开出往左往右循环找到最大的重复次数,看这个数是否大于我们当前得到的那个数(这个数是取左右区间的最大值)。

代码如下:

#include <iostream>
#include
<cmath>
#include
<stdio.h>
using namespace std;
const int N=100001;
int a[N];
struct node{
int num,cnt;
};
node m[N][
18];
void initrmq(int n)
{
int i,j;
for(i=0;i<n;i++)
m[i][
0].cnt=1;
for(j=1;(1<<j)<=n;j++)
{
for(i=0;i+(1<<j)-1<n;i++)
{
if(m[i][j-1].cnt > m[i+(1<<(j-1))][j-1].cnt)
m[i][j].cnt
=m[i][j-1].cnt;
else
m[i][j].cnt
=m[i+(1<<(j-1))][j-1].cnt;
        //多一个判断,看断开的那个数是否是重复次数最多的
int tmp=a[i+(1<<(j-1))-1];
int x=i+(1<<(j-1))-1,y=x,r=i+(1<<j)-1;
while(x>=i && (a[x]==tmp))
x
--;
while(y<=r && (a[y]==tmp))
y
++;
int tmpcnt=y-x-1;
if(tmpcnt > m[i][j].cnt)
{
m[i][j].cnt
=tmpcnt;
}
}
}
}
int queryrmq(int i,int j)
{
int k=(int)(log((j-i+1)*1.0)/(log(2.0))),rscnt;
if(m[i][k].cnt < m[j-(1<<k)+1][k].cnt)
rscnt
=m[j-(1<<k)+1][k].cnt;
else
rscnt
=m[i][k].cnt;
int tmp=a[i+(1<<k)-1];
// cout<<rscnt<<" idx "<<k<<"分开的idx"<<i+(1<<k)-1<<" "<<tmp<<endl;
int x=i+(1<<k)-1,y=x;
while(x>=i && (a[x]==tmp))
x
--;
while(y<=j && (a[y]==tmp))
y
++;
int tmpcnt=y-x-1;
// cout<<"new "<<y<<" "<<x<<" "<<tmpcnt<<endl;
if(tmpcnt > rscnt)
rscnt
=tmpcnt;
return rscnt;
}
int main()
{
int n,q,i,ans,l,r;
while(1)
{
scanf(
"%d",&n);
if(!n)
break;
scanf(
"%d",&q);
for(i=0;i<n;i++)
scanf(
"%d",&a[i]);
initrmq(n);
while(q--)
{
scanf(
"%d%d",&l,&r);
ans
=queryrmq(l-1,r-1);
printf(
"%d\n",ans);
}
}
return 0;
}
原文地址:https://www.cnblogs.com/buptLizer/p/2179743.html