uva 11235 Frequent Values

题意:给你一个长度为n的非降序排列的序列,并提出q个询问区间,i,j,请你求出[i,j]中出现次数最多的数出现的次数


这道题是最为经典的RMQ问题,我们注意到整个数组是非降序排列的,因此相同的元素肯定都聚集在一起,这样我们就可以把整个数组进行游程编码

比如 -1 1 1 2 2 2 4就可以编码成(-1,1)(1,2)(2,3)(4,1)其中(a,b)表示b个连续的a因此用cnt[i]记录第i组的元素个数,num[p],Left[p],Right[p]分别表示位置p所在的组的编号,和左右端点位置,因此每次查询[i,j]的结果为一下三个部分的最大值:

1.从i到Right[i]的元素个数

2.从j到Left[j]的元素个数

3.从第num[i]+1段到num[j]-1段的cnt的最大值

可以看到,1,2部分都可以直接算出来,第3个部分就要用到RMQ来计算了,不过要注意一下特殊情况的处理

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100005,inf=1e9;
inline void _read(int &x){
    char t=getchar();bool sign=true;
    while(t<'0'||t>'9')
    {if(t=='-')sign=false;t=getchar();}
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
    if(!sign)x=-x;
}
int n,q,r[maxn],l[maxn],cnt[maxn],num[maxn];
int Left[maxn],Right[maxn];
int f[maxn][20],type=-1,s[3];
void insert(){
	int i,j;
	for(i=0;i<type;i++)f[i][0]=cnt[i];
	for(j=1;(1<<j)<=type;j++)
	    for(i=0;i+(1<<j)<=type;i++)
	        f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int rmq(int ls,int rs){
	if(ls==rs)return cnt[ls];
	if(rs<ls)return 0;
	int k=0;
	while((1<<(k+1))<=rs-ls+1)k++;
	return max(f[ls][k],f[rs-(1<<k)+1][k]);
}
void clear(){
	memset(f,0,sizeof(f));
	memset(cnt,0,sizeof(cnt));
}
int main(){
	while(scanf("%d",&n)&&n){
		_read(q);
		int i,j;
		s[1]=inf;
		for(i=1;i<=n;i++){
			_read(s[i&1]);
			if(s[i&1^1]!=s[i&1]){
				r[type]=i-1;
				l[++type]=i;
			}
			num[i]=type;
			cnt[type]++;
		}
		r[type]=n;
		type++;
		insert();
		for(i=1;i<=n;i++){
			int t=num[i];
			Left[i]=l[t];
			Right[i]=r[t];
		}
		while(q--){
			_read(i);_read(j);
			if(num[i]==num[j])printf("%d\n",j-i+1);
			else {
				int ans=rmq(num[i]+1,num[j]-1);
				ans=max(ans,max(Right[i]-i+1,j-Left[j]+1));
				printf("%d\n",ans);
			}
		}
	}
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值