CodeForces220B - Little Elephant and Array - 莫队模板
题意
给出一个长度为\(n\)的数组,\(m\)次询问。每一次询问给出两个数\(l\)和\(r\),表示在区间\([l,r]\)内,查询在给定区间内有多少个数字,该数字出现次
数等于它本身。
思路
题目中的ai最大\(10^9\),而数组范围\(10^5\),所以如果数据大于\(10^5\)了,这个数就不可能为所求的\(x\)忽略这个数后就不用进行离散化了。
数据过大,我们无法开这么大的数组,所以要对其进行离散化处理,所以可以想到用莫队算法来解决。
AC代码
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cmath>
#include<iostream>
using namespace std;
#define inf 0x3f3f3f3f
const int N=1e5+20;
typedef long long ll;
int n,q,sum,a[N],belong[N],ans[N],cnt[N];
inline char gc() //用fread读入加快读入速度,比一般read读入要快
{
static char buf [100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
static char c=gc();
ll x=0,f=1;
for(; c>'9'||c<'0'; c=gc()) if(c=='-') f=-1;
for(; c<='9'&&c>='0'; c=gc()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
struct node
{
int l,r,id;
// bool operator < (const node &x) const
// {
// if(belong[l]==belong[x.l])
// return r<x.r;
// else
// return belong[l]<belong[x.l];
// }
} x[N];
bool cmp1(node a,node b)
{
if(belong[a.l]==belong[b.l])
return a.r<b.r;
else
// return a.l<b.l;
return belong[a.l]<belong[b.l];
}
void print(int x)
{
if(x<0)
{
putchar('-');//putchar比普通输出快
x=-x;
}
if(x>=10)
print(x/10);
putchar(x%10+'0');
printf("\n");
}
void add(int x)
{
if(a[x]>n)
return;
if(cnt[a[x]]==a[x])
sum--;
cnt[a[x]]++;
if(cnt[a[x]]==a[x])
sum++;
}
void del(int x)
{
if(a[x]>n)
return;
if(cnt[a[x]]==a[x])
sum--;
cnt[a[x]]--;
if(cnt[a[x]]==a[x])
sum++;
}
int main()
{
// n=read();
//q=read();
scanf("%d %d",&n,&q);
int block=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
//a[i]=read();
belong[i]=i/block;
}
for(int i=1; i<=q; i++)
{
scanf("%d %d",&x[i].l,&x[i].r);
// x[i].l=read();
//x[i].r=read();
x[i].id=i;//记录编号
}
sort(x+1,x+q+1,cmp1);
memset(cnt,0,sizeof(cnt));
int L=1,R=0;
for(int i=1; i<=q; i++)
{
while(x[i].l>L)
del(L++);
while(L>x[i].l)
add(--L);
while(R<x[i].r)
add(++R);
while(R>x[i].r)
del(R--);
ans[x[i].id]=sum;
}
for(int i=1; i<=q; i++)
// print(ans[i]);
printf("%d\n",ans[i]);
return 0;
}