题目描述
给定一个数组,其中的元素满足非递减顺序。任意给定一个区间[i,j],求其中某个元素重复出现的最大次数。
输入
多组数据输入。每组数据的第一行包含两个整数n和q(1<=n,q<=100000),下一行包含n个整数a1,...,an(-100000<=ai<=100000,i∈{1,...,n}),用空格分隔,数列是升序的(ai<=ai+1)。接下来的q行,每行包含两个整数i和j(1<=i<=j<=n),表示给定区间[i,j]。
输入结束于0(自成一行)。
输出
对输入的q个区间,每个区间输出一个整数表示该区间内重复最多的元素出现的次数,用换行分隔。
样例输入
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
样例输出
1
4
3
思路:前提非降序列,即所有相等的数聚在一起,所以我们可以编码一个二元组,如-1,1,1,2,2,2,4就可以编码成(-1,1),(1,2),(2,3),(4,1),其中(a,b)表示a连续出现了b次;num[i]表示第i个位置的数在哪一段,count[i]代表第i段连续的长度,Left[i],Right[i]分别表示第i段的左右端点位置;这样的话每次查询(L, R)就只要计算(Right[L]-L+1),(R-Left[R]+1)和RMQ(num[L]+1,num[R]-1)(RMQ是对count数组进行取件查询的结果)这三个值的最大值就可以了;
RMQ链接点击打开链接
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int MaxN=100000+10;
int Left[MaxN],Right[MaxN],count[MaxN],num[MaxN];
int nn,q,a,last,tot;
const int INF=0x3f3f3f3f;
//存储线段树的全局数组;
int n,dat[2*MaxN-1];
//初始化
void init(int n_)
{
//为计算方便,元素个数扩大为2的幂;
n=1;
while(n<n_) n*=2;
for(int i=0;i<2*n-1;i++)
dat[i]=-INF;
}
//n_个元素的初始化:for(int k=0;k<n_;k++) update(k,a[k]);
//把第k个值(从0开始)更新为a;
void update(int k,int a)
{
k+=n-1;
dat[k]=a;
//向上更新;
while(k>0)
{
k=(k-1)/2;
dat[k]=max(dat[2*k+1],dat[2*k+2]);
}
}
//求[a,b)的最小值;
//后面的参数是为了计算方便传入的;
//k是节点的编号,l,r表示这个节点对应的是[l,r)区间;
//外部调用时,用query(a,b,0,0,n);
int query(int a,int b,int k,int l,int r)
{
//如果[a,b)和[l,r)不相交,则返回-INF;
if(r<=a||b<=l) return -INF;
//如果[a,b)完全包含[l,r),则返回当前节点的值;
if(a<=l&&r<=b) return dat[k];
else{
//否则返回两个儿子中值的较大者;
int vl=query(a,b,k*2+1,l,(l+r)/2);
int vr=query(a,b,k*2+2,(l+r)/2,r);
return max(vl,vr);
}
}
int main(){
while(~scanf("%d", &nn) && nn)
{
scanf("%d", &q);
tot = 0;
for(int i=1;i<=nn;i++)
{
scanf("%d", &a);
if(i==1)
{
last=a;
Left[tot]=1;
}
if(last==a)
{
num[i]=tot;
count[tot]++;
Right[tot]++;
}
else
{
num[i]=++tot;
count[tot]++;
Left[tot]=Right[tot]=i;
last=a;
}
}
init(tot+1);
for(int k=0;k<=tot;k++)
update(k,count[k]);
int l, r;
for(int i=0;i<q;i++)
{
scanf("%d%d", &l, &r);
if(num[l] == num[r]) { printf("%d\n", r-l+1); continue; }
printf("%d\n", max( query(num[l]+1,num[r]-1+1,0,0,n), max( Right[num[l]]-l+1, r-Left[num[r]]+1 ) ) );
}
}
return 0;
}