UVA-11235 Frequent values (RMQ)

题目大意:在一个长度为n的不降序列中,有m次询问,每次询问(i,j)表示在区间(i,j)中找出出现次数最多的元素的出现次数。

题目分析:因为序列有序,可以将序列分段,并且记录每段的元素个数、每一个元素所属的段num(i)、每一个元素所属段的左端点l(i)及右端点r(i)。那么对于每次询问:

ans(i,j)=max(max(r(i)-i+1,j-l(j)+1),rmq(num(i)+1,num(j)-1))。

ans(i,j)=r-j+1  (如果i与j属于同一段)

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<vector>
# include<queue>
# include<list>
# include<set>
# include<map>
# include<string>
# include<cmath>
# include<cstdlib>
# include<algorithm>
using namespace std;
# define LL long long

const int N=1005;
const int INF=1000000000;
const LL oo=0x7fffffffffffffff;
const double eps=1e-10;

int n,m;
int a[N*100];
vector<int>v;
int num[N*100];
int L[N*100];
int R[N*100];
int d[N*100][20];

void RMQ_init()
{
	int len=v.size();
	for(int i=0;i<len;++i) d[i][0]=v[i];
	for(int j=1;(1<<j)<=len;++j)
		for(int i=0;i+(1<<j)-1<len;++i)
			d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}

void init()
{
	v.clear();
	int cnt=1;
	num[0]=0;
	L[0]=0;
	for(int i=1;i<n;++i){
		if(a[i]==a[i-1]){
			++cnt;
			num[i]=num[i-1];
			L[i]=L[i-1];
		}else{
			v.push_back(cnt);
			num[i]=v.size();
			L[i]=i;
			cnt=1;
		}
	}
	v.push_back(cnt);
	R[n-1]=n-1;
	for(int i=n-2;i>=0;--i){
		if(a[i]==a[i+1])
			R[i]=R[i+1];
		else
			R[i]=i;
	}
	RMQ_init();
}

int query(int l,int r)
{
	if(l>r) return 0;
	int k=0;
	while((1<<(k+1))<=r-l+1) ++k;
	return max(d[l][k],d[r-(1<<k)+1][k]);
}

int solve(int l,int r)
{
	if(num[l]==num[r])
		return r-l+1;
	else{
		return max(max(R[l]-l+1,r-L[r]+1),query(num[l]+1,num[r]-1));
	}
}

int main()
{
	while(scanf("%d",&n)&&n)
	{
		scanf("%d",&m);
		for(int i=0;i<n;++i)
			scanf("%d",a+i);
		init();
		int l,r;
		while(m--)
		{
			scanf("%d%d",&l,&r);
			--l,--r;
			printf("%d\n",solve(l,r));
		}
	}
	return 0;
}

  

posted @ 2016-04-26 23:02  20143605  阅读(273)  评论(0编辑  收藏  举报