uva 11235 Frequent Values

来源:互联网 发布:ubuntu ntfs-3g 编辑:程序博客网 时间:2024/05/16 06:23

题意:给你一个长度为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
原创粉丝点击