Description
给定 \(n\) 个数组成的数列,\(m\) 次询问
对于每次询问求出在给定的 \(L\) 到 \(R\) 的范围内有多少个数字的出现频率等于其本身
Solution
莫队
根据数据范围 \(1\le n,m \le 1e5\),\(a_i\le 1e9\) 可知
当序列中某个数大于 \(1e5\) 时,他的出现频率不可能等于其大小,对答案无贡献
因此,对大于 \(1e5\) 的数,预处理为 \(0\)
然后
对于缩进操作,显然是删去当前点的贡献,再添加缩进之后的贡献,当删除的数等于其频率时,他的贡献会丢失,反之,如果删除之后才等于其频率,他的贡献可以增加
对于扩展操作原理亦是如此,只是先扩展再添加新贡献
另外要判断一下改变的数是否为预处理过的 \(0\)
Code
#include<bits/stdc++.h>
#define maxn 1001000
#define rr register
//#define int long long
using namespace std;
int n,val[maxn],q,L,R=-1,sq,ans,siz[maxn],Res[maxn];
struct node{int l,r,id;}Ask[maxn];
inline int read() {
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return w*s;
}
inline void write(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
void Del(int x){if(val[x]==0) return;ans-=(--siz[val[x]]==val[x]-1);ans+=(siz[val[x]]==val[x]);}
void Add(int x){if(val[x]==0) return;ans-=(++siz[val[x]]==val[x]+1);ans+=(siz[val[x]]==val[x]);}
inline int Cmp(node x,node y){return x.l/sq==y.l/sq?((x.l/sq)&1)?x.r<y.r:x.r>y.r:x.l/sq<y.l/sq;}
signed main(){
n=read();q=read();sq=sqrt(n+0.5);
for(rr int i=1;i<=n;i++){
val[i]=read();
if(val[i]>100000) val[i]=0;
}
for(rr int i=1;i<=q;i++) Ask[i].l=read(),Ask[i].r=read(),Ask[i].id=i;
sort(Ask+1,Ask+1+q,Cmp);
for(rr int i=1;i<=q;i++){
while(L>Ask[i].l){Add(--L);}
while(R<Ask[i].r){Add(++R);}
while(L<Ask[i].l){Del(L++);}
while(R>Ask[i].r){Del(R--);}
Res[Ask[i].id]=ans;
}
for(int i=1;i<=q;i++) printf("%d\n",Res[i]);
return 0;
}