莫队 Little Elephant and Array
题目链接:Problem - B - Codeforces
题目大意:
给一个长度为 n (n <= 1e5) 的数组 (ai <= 1e9),m (m <= 1e5) 次询问,每次查询一个区间 [l,r] ,求区间内有多少个数 x ,满足 x 在这个区间的出现次数也刚好等于 x 。
Solution:
注意到答案可以离线,考虑莫队,可以算是模板题了。
我们要维护每个数出现的次数,但是 ai <= 1e9 太大了,无法维护所有的数。不过好在 ai > n 的数其实是不需要维护的,因为他们永远不可能出现那么多次嘛。
莫队的主要思想就是:分块 + 排序询问 + 移动区间
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;#define N 100005int n,m,B;
int a[N],bel[N],cnt[N],ans[N],res;struct Query
{int l,r,id;
}q[N];int cmp(Query x,Query y)
{if(bel[x.l] == bel[y.l]) return x.r < y.r ;return bel[x.l] < bel[y.l] ;
}void add(int x)
{if(a[x] > n) return;if(cnt[a[x]] == a[x]) -- res;++ cnt[a[x]];if(cnt[a[x]] == a[x]) ++ res;return;
}void sub(int x)
{if(a[x] > n) return;if(cnt[a[x]] == a[x]) -- res;-- cnt[a[x]];if(cnt[a[x]] == a[x]) ++ res;return;
}int main()
{scanf("%d%d",&n,&m);B = (int)sqrt(n);for (int i = 1;i <= n;++ i) scanf("%d",&a[i]),bel[i] = (i - 1) / B + 1;for (int i = 1;i <= m;++ i){scanf("%d%d",&q[i].l,&q[i].r);q[i].id = i;}sort(q + 1,q + m + 1,cmp);int l,r;l = 1,r = res = 0;for (int i = 1;i <= m;++ i){while (l > q[i].l) add(-- l);while (l < q[i].l) sub(l ++);while (r < q[i].r) add(++ r);while (r > q[i].r) sub(r --);ans[q[i].id] = res;}for (int i = 1;i <= m;++ i) printf("%d\n",ans[i]);return 0;
}