题目链接:B. Little Elephant and Array
input
7 2
3 1 2 2 3 3 7
1 7
3 4
output
3
1
题意:
给你一个长度为n的数组,然后m次询问,
每次询问L,R,范围内的总共有多少个出现次数和他数值本身相等的数。
思路:
确实是莫队的板子题,(莫队这个坑,去年到今年一直没填,正好具体的学一下思想和一些小方法)
有一篇大佬的博客讲的不错:莫队算法详解
莫队,优雅的暴力,分块改变了查询的顺序,划定了每一块要查询的范围,就只是这样顺序搞了一下,竟然可以让我们本来
o
(
n
2
)
o(n^2)
o(n2)的复杂度降到了
o
(
n
√
n
)
o(n√n)
o(n√n)。前面的范围控制在同一块的范围内,然后同一块中的后边界从小到大,在正确的情况下也降低了不少时间复杂度。
这样可以过掉很多题。莫队是一种强制离线的操作。
理解了莫队它优化时间的思想,这道题就很好的可以去练练手,就开个数组记录这个数的出现的次数就行了,一道很好的板题。
AC
#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
const int N=1e5+10;
struct zxc
{
LL l,r,id;
}md[N];
LL num[N];
LL L=1,R=0;
LL n,m;
LL fk;
LL a[N];
bool cmp(zxc q,zxc w)
{
if((q.l/fk)==(w.l/fk))
{
return q.r<w.r;
}
else
{
return q.l<w.l;
}
}
LL ans[N];
int main()
{
scanf("%lld%lld",&n,&m);
for(LL i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(LL i=1;i<=m;i++)
{
scanf("%lld%lld",&md[i].l,&md[i].r);
md[i].id=i;
}
fk=sqrt(n);
sort(md+1,md+1+m,cmp);
LL ax=0;
for(LL i=1;i<=m;i++)
{
while(L<md[i].l)
{
if(a[L]<=100000)
{
num[a[L]]--;
if(num[a[L]]==a[L])
{
ax++;
}
if(num[a[L]]==a[L]-1)
{
ax--;
}
}
L++;
}
while(L>md[i].l)
{
L--;
if(a[L]<=100000)
{
num[a[L]]++;
if(num[a[L]]==a[L])
{
ax++;
}
if(num[a[L]]==a[L]+1)
{
ax--;
}
}
}
while(R<md[i].r)
{
R++;
if(a[R]<=100000)
{
num[a[R]]++;
if(num[a[R]]==a[R])
{
ax++;
}
if(num[a[R]]==a[R]+1)
{
ax--;
}
}
}
while(R>md[i].r)
{
if(a[R]<=100000)
{
num[a[R]]--;
if(num[a[R]]==a[R])
{
ax++;
}
if(num[a[R]]==a[R]-1)
{
ax--;
}
}
R--;
}
ans[md[i].id]=ax;
}
for(LL i=1;i<=m;i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}