链接
题目描述
给出一个有n个正整数的序列A,m次询问,每次询问一段区间[l,r]内大小在[a,b]内的不同的数的个数。
思路
莫队记录不同颜色的数量,然后用树状数组记录颜色的区间
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n, m;
int ans[1000005], pos[1000005], v[100005], cnt[1000006], d[1000005];
struct tt
{
int l, r, x, y, id;
}q[10000005];
int read()
{
int x = 0, flag = 1; char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') flag = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0'; ch = getchar();}
return x * flag;
}
void write(int x)
{
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
return;
}
bool cmpd(tt a, tt b)
{
return a.id < b.id;
}
bool cmpp(tt a, tt b)
{
if(pos[a.l] != pos[b.l]) return pos[a.l] < pos[b.l];
if(pos[a.l] & 1) return a.r > b.r;
return a.r < b.r;
}
void update(int x, int t)
{
for(; x <= n; x += x & (-x)) cnt[x] += t;}
int sum(int x)
{
int res = 0;
for(; x; x -= x & (-x)) res += cnt[x];
return res;
}
void add(int x)
{
if(!d[v[x]]) update(v[x], 1);
++d[v[x]];
}
void del(int x)
{
if(d[v[x]] == 1) update(v[x], -1);
--d[v[x]];
}
void MD()
{
int le = 1, ri = 0;
for(int i = 1; i <= m; ++i)
{
while(le < q[i].l) del(le++);
while(le > q[i].l) add(--le);
while(ri < q[i].r) add(++ri);
while(ri > q[i].r) del(ri--);
ans[q[i].id] = sum(q[i].y) - sum(q[i].x - 1);
}
}
int main()
{
n = read(); m = read();
int size = sqrt(n);
for(int i = 1; i <= n; ++i)
v[i] = read(), pos[i] = (i - 1) / size + 1;
for(int i = 1; i <= m; ++i)
{
q[i].l = read(); q[i].r = read();
q[i].x = read(); q[i].y = read();
q[i].id = i;
}
sort(q + 1, q + m + 1, cmpp);
MD();
for(int i = 1; i <= m; ++i)
printf("%d\n", ans[i]);
return 0;
}