题目描述
给定一个数组,其中的元素满足非递减顺序。任意给定一个区间[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
思路:
问题保证数据递增,那么我们这里将数据离散化之后,暴力查询下标即可。
在查询之前,我们需要将和a【L】相同的左边的数的个数去掉,以及将和a【R】相同的右边的数的个数去掉。
那么我们维护一个数组num【i】,表示num【i】是这一串连续相等的数字中第几个。
并且统计好cont【i】表示离散化之后编号为i的数字的个数即可。
那么删除的左边的元素的个数就是num【i】-1.
那么删除的右边的元素的个数就是cont【i】-num【i】;
过程线段树维护一下。
注意该OJ没有开O2加速,所以Map会TLE,数据离散化用数组标记吧= =
Ac代码:
#include<stdio.h>
#include<string.h>
#include<map>
using namespace std;
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
int tree[1000050*8];
int a[150000];
int num[150000];
void pushup(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int Query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return tree[rt];
}
else
{
int m=(l+r)>>1;
int ans=0;
if(L<=m)
{
ans=max(Query(L,R,lson),ans);
}
if(m<R)
{
ans=max(Query(L,R,rson),ans);
}
return ans;
}
}
void build( int l ,int r , int rt )
{
if( l == r )
{
tree[rt]=0;
return ;
}
else
{
int m = (l+r)>>1 ;
build(lson) ;
build(rson) ;
pushup(rt) ;
}
}
void update(int p,int c,int l,int r,int rt)
{
if(l==r)
{
tree[rt]+=c;
}
else
{
int m=(l+r)>>1;
if(p<=m) update(p,c,lson);
else update(p,c,rson);
pushup(rt);
}
}
int s[350000];
int cont[350000];
int main()
{
int n,q;
while(~scanf("%d",&n))
{
if(n==0)break;
scanf("%d",&q);
int cnt=0;
memset(s,0,sizeof(s));
memset(cont,0,sizeof(cont));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i==0||a[i]!=a[i-1])
{
s[i]=++cnt;
num[i]=1;
}
else num[i]=num[i-1]+1,s[i]=s[i-1];
cont[s[i]]++;
}
build(1,n,1);
for(int i=1;i<=n;i++)update(s[i],1,1,n,1);
for(int i=0;i<q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
update(s[l],1-num[l],1,n,1);
update(s[r],-(cont[s[r]]-num[r]),1,n,1);
printf("%d\n",Query(s[l],s[r],1,n,1));
update(s[l],-(1-num[l]),1,n,1);
update(s[r],(cont[s[r]]-num[r]),1,n,1);
}
}
return 0;
}