题目大意:(n)个数,(m)个询问,每次四个参数,(l,r,a,b),问区间([l,r])中出现过的,数值在([a,b])区间中的数的个数以及区间([l,r])中数值在([a,b])中的数的个数。
注意理解 这两个是不一样的。
( ext{Solution:})
观察到区间颜色出现次数可以想到莫队。
由于多了一个限制,那么我们考虑如何更新答案,并利用前缀思想:
指针移动的时候,维护颜色数以及这个颜色的值,对应在一个树状数组上更新。注意维护两个树状数组,分别处理两个询问。其他的和普通莫队没什么区别。
复杂度(O(nsqrt{n}log n).)此处替换(m)因为它们同阶。
其实还有莫队套分块的更优复杂度以及(KDT,cdq)分治等多种做法,在此不做赘述。
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
const int MAXN=1e6+10;
int col[MAXN],cnt[MAXN],a[MAXN],n,m,tr[MAXN];
int bl[MAXN],siz,bnum,now,tr1[MAXN];
pair<int,int>ans[MAXN];
inline bool R(char C){return C>='0'&&C<='9';}
inline int read(){
int s=0;
char ch=getchar();
while(!R(ch))ch=getchar();
while(R(ch))s=s*10+ch-48,ch=getchar();
return s;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>=10)write(x/10);
putchar(x%10+48);
}
struct Q{
int l,r,a,b,id;
}q[MAXN];
inline bool cmp(Q a,Q b){return (bl[a.l]^bl[b.l])?bl[a.l]<bl[b.l]:(bl[a.l]&1)?a.r<b.r:a.r>b.r;}
inline void change(int x,int v){for(;x<=n;x+=lowbit(x))tr[x]+=v;}
inline int sum(int x){int res=0;for(;x;x-=lowbit(x))res+=tr[x];return res;}
inline void change2(int x,int v){for(;x<=n;x+=lowbit(x))tr1[x]+=v;}
inline int sum2(int x){int res=0;for(;x;x-=lowbit(x))res+=tr1[x];return res;}
inline void del(int x){
--cnt[a[x]];
if(!cnt[a[x]])now--,change(a[x],-1);
change2(a[x],-1);
}
inline void add(int x){
if(!cnt[a[x]])change(a[x],1),now++;
++cnt[a[x]];change2(a[x],1);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)a[i]=read();
siz=sqrt(n);bnum=ceil((double)n/siz);
for(int i=1;i<=bnum;++i)for(int j=(i-1)*siz+1;j<=i*siz;++j)bl[j]=i;
for(int i=1;i<=m;++i){
q[i].id=i;
q[i].l=read();
q[i].r=read();
q[i].a=read();
q[i].b=read();
}
sort(q+1,q+m+1,cmp);
int l=1,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--);
ans[q[i].id].first=sum2(q[i].b)-sum2(q[i].a-1);
ans[q[i].id].second=sum(q[i].b)-sum(q[i].a-1);
}
for(int i=1;i<=m;++i)write(ans[i].first),putchar(' '),write(ans[i].second),putchar('
');
return 0;
}