UVA11235 Frequent values

Frequent values

双倍经验:

UVA11235

SP1684

求区间众数的出现次数。

Analysis 分析

莫队。

Solution 莫队

考虑扩展和删除一个数。

\(add:\)

扩展一格是简单的,只需要记一个数组 \(cnt_x\) 代表 \(x\) 出现的次数,用来更新当前答案 \(res\) 即可。

\(del:\)

删除一格我们发现只记一个数组 \(cnt_x\) 是不够的。我们再引入 \(tot_x\) 代表出现了 \(x\) 次的数有几个。

这时 \(cnt_x=res\)\(tot_{cnt_x}=0\) ,如果两个条件都满足,就表示众数的个数少了一个,即 \(res--\)

观察到 \(a_i\) 值域包含负数,可以把所有的 \(a_i\) 都加上 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;
}
posted @ 2024-05-31 21:59  Mr_Azz  阅读(6)  评论(0编辑  收藏  举报