POJ 3368 Frequent Values(RMQ)
http://poj.org/problem?id=3368
题意:
给出一个非降序排列的整数数组a1,a2,...an,你的任务是对于一系列询问(i, j),回答ai,ai+1,...aj中出现最多次数的值所出现的次数?
分析:刘汝佳:训练指南P198
1. 本题主要思想是把输入序列分成一段段由相同值构成的序列,然后对于每个查询[L,R]看他覆盖了那些段,只要再这些连续的段范围内找出现次数的最大值即可,即RMQ问题
2. 由于a[n]是升序排列的,所以给a数组游程编码为(v,num)其中v是a[i]的值,num是v这个相同的值出现的次数。用RMQ维护一个数组d[j]=num,表示从左到右出现的所有值中第j个出现的值连续出现了num次。
3. 然后给每一个a[i]建立num[i], left[num[i]] , right[num[i]],分别表示:
a[i]的值在所有出现的值中是在第num[i]个出现的(num[i]就是分析1中a[i]值的出现次数在RMQ中的编号j)
与a[i]值相同的连续值最左边的那个是位于left[num[i]]位置,最右边的那个是位于right[num[i]]位置,并且。
4. 对于一个查询[L,R],首先求出L,和R分别属于个num[],如果num[L]==num[R],那么ans=R-L+1
否则,与L相同的值出现了right[num[L]]-L+1次,与R相同的值出现了
R-left[num[R]]+1次,在L与R中间(如果有的话)的值最多出现了
GetMax(num[L]+1,num[R]-1)次
5. 最终结果就是
MAX(right[num[L]]-L+1 ,R-left[num[R]]+1 ,GetMax(num[L]+1,num[R]-1))
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN =200000+1000;
int dmax[MAXN][20];
int a[MAXN];
int left[MAXN],right[MAXN],num[MAXN];
int d[MAXN];//d[i]=8表第i个不同的值出现了8次
void initmax(int n,int d[])
{
for(int i=1;i<=n;i++)
dmax[i][0]=d[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dmax[i][j]=max( dmax[i][j-1],dmax[i+(1<<(j-1))][j-1] );
}
int getmax(int L,int R)
{
int k=0;
while(1<<(k+1)<=R-L+1)k++;
return max(dmax[L][k],dmax[R+1-(1<<k)][k]);
}
int main()
{
int n,q;
while(scanf("%d",&n)==1&&n)
{
memset(d,0,sizeof(d));
scanf("%d",&q);
scanf("%d",&a[1]);
int cnt=1;//表示当前出现了多少个不同的值
left[cnt]=1;//第cnt段最左边是位置1
right[cnt]=1;//第cnt段最右边是位置1
num[1]=cnt;//第一个元素属于第cnt段
d[cnt]=1;//第cnt段目前有1个元素
for(int i=2;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==a[i-1])
{
num[i]=cnt;
right[cnt]=i;
d[cnt]++;
}
else//出现新值
{
num[i]=++cnt;
left[cnt]=i;
right[cnt]=i;
d[cnt]=1;
}
}
initmax(n,d);//注意
while(q--)
{
int L,R;
scanf("%d%d",&L,&R);
int num_L=num[L],num_R=num[R];
if(num_L==num_R)
printf("%d\n",R-L+1);
else
{
int temp1=right[num[L]]-L+1;//a[L]出现的次数
int temp2=R-left[num[R]]+1;//a[R]出现的次数
int temp3=0;
if(num_R-num_L>1)
temp3 = getmax(num_L+1,num_R-1);
int ans = max(temp3,max(temp1,temp2));
printf("%d\n",ans);
}
}
}
return 0;
}
</span>