题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=6959
分析
求出每个查询的[x0, x1]区间中所有数出现的次数,可以用莫队。然后维护一个树状数组来查询[y0, y1]区间中出现的数的种类(出现过为1,否则为0)。
代码
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define MP make_pair
#define pb push_back
typedef long long ll;
int n,m;
int a[100005], c[100005];
int res[100005],cnt[100005],unit;
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){
int res = 0;
while(i > 0){
res += c[i];
i -= lowbit(i);
}
return res;
}
void add(int x)
{
if(!cnt[a[x]]) updata(a[x], 1);
cnt[a[x]]++;
}
void del(int x)
{
cnt[a[x]]--;
if(!cnt[a[x]]) updata(a[x], -1);
}
struct node{
int id,l,r,a,b;
bool operator < (const node & x) const
{
if(l / unit != x.l / unit) return l < x.l;
if((l / unit) & 1) return r < x.r;
return r > x.r;
}
}q[100005];
int main ()
{
int T = 1;
scanf("%d",&T);
while(T--)
{
for(int i=1;i<=100001;i++) cnt[i] = 0;
scanf("%d%d",&n,&m);
unit = n / sqrt(m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]), a[i]++, c[i] = 0;
for(int i=1;i<=m;i++) scanf("%d%d%d%d",&q[i].l,&q[i].a,&q[i].r,&q[i].b), q[i].id = i, q[i].a++, q[i].b++;
sort(q+1, q+1+m);
int l = 0, r = 0;
for(int i=1;i<=m;i++)
{
int ql = q[i].l, qr = q[i].r;
while(l < ql) del(l++);
while(l > ql) add(--l);
while(r < qr) add(++r);
while(r > qr) del(r--);
res[q[i].id] = getsum(q[i].b) - getsum(q[i].a - 1);
}
for(int i=1;i<=m;i++)
{
printf("%d\n",res[i]);
}
}
return 0;
}