UVA11235 Frequent values
Frequent values
双倍经验:
求区间众数的出现次数。
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;
}