这道题巧妙地运用到了分块和莫队两种算法的结合。对于1-n的每一个X都有一个w[i]来代表其高度,然后其实这道题就是在之前的普通莫队的基础上在你统计出来每一个只有多少个之后,再去数出在对定范围内的值有几种。
对于每一个x轴上的移动,我们可以按莫队去计算,然后对于每一个查询,我们的答案可以用分块的思想去在sqrt(n)的时间内查询出来。
其实这道题难得地方就在于思维转化,对于一个二维的查询,我们要把他降为一维,一个y其实就相当于是这个点的权重,想到这里这道题就迎刃而解了。
时间复杂度等于莫队:Q*sqrt(n)+n*sqrt(n) +分块查询 Q*sqrt(maxn)
然后对于要想实现分块查询,我们就要多设一个sum数组,去统计一个块内共有几种不同的y值
这里的cnt数组就相当于a数组,sum数组就相当于Lazy数组。
void sub(int x){
if(--cnt[x] == 0) sum[pos[x]]--;
}
void add(int x){
if(cnt[x]++ == 0) sum[pos[x]]++;
}
查询时是用分块思想
int query(int l,int r){
int res=0;
for(int i = l ; i <= min(r,BK2(l)) ; i++){
if(cnt[i] >= 1) res++;
}
if(pos[l] != pos[r]){
for(int i = BK1(r) ; i <= r ; i++){
if(cnt[i] >= 1) res++;
}
}
for(int i = pos[l]+1 ; i <= pos[r]-1 ; i++){
res+=sum[i];
}return res;
}
然后总的代码是:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define BK1(x) ((pos[x]-1)*bk+1)
#define BK2(x) (pos[x]*bk)
using namespace std;
const int maxn = 1e5+10;
int n,k,w[maxn],bk,pos[maxn],sum[maxn],cnt[maxn],ans[maxn];
struct node{
int xl,yl,xr,yr,id;
}a[maxn];
void sub(int x){
if(--cnt[x] == 0) sum[pos[x]]--;
}
void add(int x){
if(cnt[x]++ == 0) sum[pos[x]]++;
}
int query(int l,int r){
int res=0;
for(int i = l ; i <= min(r,BK2(l)) ; i++){
if(cnt[i] >= 1) res++;
}
if(pos[l] != pos[r]){
for(int i = BK1(r) ; i <= r ; i++){
if(cnt[i] >= 1) res++;
}
}
for(int i = pos[l]+1 ; i <= pos[r]-1 ; i++){
res+=sum[i];
}return res;
}
void solve(){
memset(cnt,0,sizeof cnt);
memset(sum,0,sizeof sum);
bk=sqrt(n);
for(int i = 1; i <= n ; i++){
scanf("%d",&w[i]);
pos[i]=(i-1)/bk+1;
}
for(int i = 1; i <= k ; i++){
scanf("%d %d %d %d",&a[i].xl,&a[i].yl,&a[i].xr,&a[i].yr);
a[i].id=i;
}
sort(a+1,a+k+1,[](node x,node y){
if(pos[x.xl]!=pos[y.xl]) return pos[x.xl] < pos[y.xl];
if(pos[x.xl]&1) return x.xr < y.xr;
return x.xr > y.xr;
});
for(int i = 1,R=0,L=1; i <= k ; i++){
int l=a[i].xl,r=a[i].xr;
while(L<l) sub(w[L++]);
while(L>l) add(w[--L]);
while(R>r) sub(w[R--]);
while(R<r) add(w[++R]);
ans[a[i].id]=query(a[i].yl,a[i].yr);
}
for(int i = 1; i <= k ; i++){
printf("%d\n",ans[i]);
}
}
int main()
{
int t;scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&k);
solve();
}
return 0;
}