一般思路是权值线段树或者莫队来做。
这里选择莫队来做。(因为我菜呐,如果是比赛的时候,只能写个暴力尽可能多拿分了)
题解区看到权值线段树因为没考虑清楚被卡掉2-3个点不等,心里挺happy的,这样我们写莫队这个简单的暴力算法就由不亏到赚翻了。
需要求区间出现次数最多数出现的次数,那么我们对于每个不同的数,首先记录一个cnt,cnt[x]表示x目前出现的次数;然后对于每个不同的次数,再记录一个sum,sum[x]表示出现x次的数有几个。
那么,在add和del中,都是先把当前次数的sum[cnt[a[x]]]减一,然后更新cnt[a[x]],最后把更新后的sum[cnt[a[x]]]加一。
其中,再根据答案和cnt[a[x]]的关系以及sum[cnt[a[x]]],更新即可。
莫队居然不开O2就过了,更赚了…
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,t,nowl,nowr,now;
int a[N],sum[N],cnt[N],ans[N];
struct number{int x,y,id;}num[N];
inline bool cmp(number a,number b)
{
if (a.x/t<b.x/t) return true;
if (a.x/t==b.x/t && a.y<b.y) return true;
return false;
}
inline void add(int x)
{
sum[cnt[a[x]]]--;
cnt[a[x]]++;
now=max(now,cnt[a[x]]);
sum[cnt[a[x]]]++;
}
inline void del(int x)
{
sum[cnt[a[x]]]--;
if (now==cnt[a[x]] && !sum[cnt[a[x]]]) now--;
cnt[a[x]]--;
sum[cnt[a[x]]]++;
}
int main(){
scanf("%d%d",&n,&m);
for (register int i=1; i<=n; ++i) scanf("%d",&a[i]),a[i]+=1e5+1;
for (register int i=1; i<=m; ++i) scanf("%d%d",&num[i].x,&num[i].y),num[i].id=i;
t=(int)sqrt(n);
sort(num+1,num+m+1,cmp);
nowl=num[1].x; nowr=num[1].y;
for (register int i=nowl; i<=nowr; ++i) add(i);
ans[num[1].id]=now;
for (register int i=2; i<=m; ++i)
{
while (nowl<num[i].x) del(nowl),nowl++;
while (nowl>num[i].x) nowl--,add(nowl);
while (nowr<num[i].y) nowr++,add(nowr);
while (nowr>num[i].y) del(nowr),nowr--;
ans[num[i].id]=now;
}
for (register int i=1; i<=m; ++i) printf("%lld\n",ans[i]);
return 0;
}