洛谷 P1997 faebdc 的烦恼

一般思路是权值线段树或者莫队来做。
这里选择莫队来做。(因为我菜呐,如果是比赛的时候,只能写个暴力尽可能多拿分了)
题解区看到权值线段树因为没考虑清楚被卡掉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;	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值