题目大意:
给出一段长度 n n n的序列, m m m一个询问,每个询问给出区间 [ l , r ] [l,r] [l,r],求 [ l , r ] [l,r] [l,r]有多少数字符合数量? x x x,也是出现次数 x x x
n , m < = 1 e 5 n,m<=1e5 n,m<=1e5
分析:
用莫队解决询问排序问题 注意数 x x x出现 x x x次-> x 1 x 1 x 1次变及 x x x次-> x − 1 x-1 x−1次的变化即可
代码:
#include <bits/stdc++.h>
#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define N 100005
using namespace std;
typedef long long ll;
struct Node {
int l, r, id;
}q[N];
int beln[N], cid[N], a[N], b[N], cnt[N], n, m, bis, now;
int ans[N];
bool orz1[N], orz2[N];
void read(int &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') {
if (s == '-') f = - 1; s = getchar(); }
while (s >= '0' && s <= '9') {
x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
bool cmp(Node aa, Node bb) {
return (beln[aa.l] == beln[bb.l]) ? ((beln[aa.l] & 1) ? aa.r < bb.r : aa.r > bb.r): beln[aa.l] < beln[bb.l];
}
void add(int x) {
if (!x || x > n) return;
if (cnt[cid[x]] == a[x]) --now;
++cnt[cid[x]];
if (cnt[cid[x]] == a[x]) ++now;
}
void del(int x) {
if (!x || x > n) return;
if (cnt[cid[x]] == a[x]) --now;
--cnt[cid[x]];
if (cnt[cid[x]] == a[x]) ++now;
}
int main() {
read(n); read(m);
rep(i, 1, n) read(a[i]), b[i] = a[i];
sort(b+1, b+n+1);
bis = unique(b+1, b+n+1)-b-1;
rep(i, 1, n) cid[i] = lower_bound(b+1, b+bis+1, a[i])-b;
rep(i, 1, m) read(q[i].l), read(q[i].r), q[i].id = i;
int siz = sqrt(n);
rep(i, 1, n) beln[i] = (i-1)/siz+1;
sort(q+1, q+m+1, cmp);
int l = 1, r = 0; now = 0;
rep(i, 1, m) {
while (l < q[i].l) del(l), l++;
while (l > q[i].l) l--, add(l);
while (r < q[i].r) r++, add(r);
while (r > q[i].r) del(r), r--;
ans[q[i].id] = now;
}
rep(i, 1, m) printf("%d\n", ans[i]);
return 0;
}