Frequent values

Frequent values

双倍经验:

UVA11235

SP1684

求区间众数的出现次数。

Analysis 分析

莫队。

Solution 莫队

考虑扩展和删除一个数。

a d d : add: add:

扩展一格是简单的,只需要记一个数组 c n t x cnt_x cntx 代表 x x x 出现的次数,用来更新当前答案 r e s res res 即可。

d e l : del: del:

删除一格我们发现只记一个数组 c n t x cnt_x cntx 是不够的。我们再引入 t o t x tot_x totx 代表出现了 x x x 次的数有几个。

这时 c n t x = r e s cnt_x=res cntx=res t o t c n t x = 0 tot_{cnt_x}=0 totcntx=0 ,如果两个条件都满足,就表示众数的个数少了一个,即 r e s − − res-- res

观察到 a i a_i ai 值域包含负数,可以把所有的 a i a_i ai 都加上 1e5。

同时注意莫队移动的顺序。

Code 代码

int n,T,blo,res=-1;
int a[N],ans[N];
int cnt[N*2],tot[N*2];//cnt[x]: x出现的次数 tot[x]: 出现次数为x的数的个数
inline int num(int x){return x/blo;}
struct ask{
	int l,r,id;
	bool operator<(const ask &A)const{
		if(num(l)!=num(A.l)) return num(l)<num(A.l);
		return (num(A.l)&1)?r<A.r:r>A.r;
	}
}q[N];
inline void add(int x){
	x=a[x];
	tot[cnt[x]]--;cnt[x]++;tot[cnt[x]]++;
	res=max(res,cnt[x]);
	return ;
}
inline void del(int x){
	x=a[x];
	tot[cnt[x]]--;
	if(cnt[x]==res&&tot[cnt[x]]==0) res--;
	cnt[x]--;tot[cnt[x]]++;
	return ;
}
int main(){
	while(1){
		res=-1;
		read(n);
		if(!n) return 0;//多测退出
		read(T);
        mem(tot,0);mem(cnt,0);//多测清空
		blo=sqrt(n);
		for(rint i=1;i<=n;i++) read(a[i]),a[i]+=N;
		for(rint i=1;i<=T;i++){
			int x,y;read(x,y);
			q[i]={x,y,i};
		}
		sort(q+1,q+T+1);
		int l=1,r=0;	
		for(rint i=1;i<=T;i++){
            //注意转移顺序,会T
	        while(l<q[i].l) del(l++);
	        while(l>q[i].l) add(--l);
	        while(r>q[i].r) del(r--);
	        while(r<q[i].r) add(++r);
	        ans[q[i].id]=res;
	    }
	    for(rint i=1;i<=T;i++) printf("%lld\n",ans[i]); 
	}
    return 0;
}
  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值