
【题解】
使用莫队算法。开一个权值树状数组维护区间内数值种类。
扩展时间是$logN$,所以总的时间复杂度是$O(n*sqrt{n}*logn)$.勉强卡过去。
用分块可以更快。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define M (1000010)
#define N (100010)
#define rg register
#define lowbit (x&-x)
using namespace std;
int n,m,x,y,cnt[N],t[N],a[N],bl[N],ans[M];
struct queue{
int l,r,x,y,pos;
}q[M];
inline int read(){
int k=0,f=1; char c=getchar();
while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
return k*f;
}
inline bool cmp(queue a,queue b){
if(bl[a.l]==bl[b.l]){
if(bl[a.l]&1) return a.r<b.r;
else return a.r>b.r;
}
return bl[a.l]<bl[b.l];
}
inline void add(int x,int del){for(;x<=n;x+=lowbit) t[x]+=del;}
inline int query(int x){
int ret=0;
for(;x>=1;x-=lowbit) ret+=t[x];
return ret;
}
inline void move(int pos,int del){
if(del==1){
if(!cnt[a[pos]]) add(a[pos],1);
cnt[a[pos]]++;
}
else{
cnt[a[pos]]--;
if(!cnt[a[pos]]) add(a[pos],-1);
}
}
int main(){
n=read(); m=read();
int block=sqrt(n);
for(rg int i=1;i<=n;i++) a[i]=read(),bl[i]=(i-1)/block+1;
for(rg int i=1;i<=m;i++){
q[i].l=read(); q[i].r=read();
q[i].x=read(); q[i].y=read();
q[i].pos=i;
}
sort(q+1,q+1+m,cmp);
for(rg int i=1,l=1,r=0;i<=m;i++){
while(l<q[i].l) move(l++,-1);
while(l>q[i].l) move(--l,1);
while(r<q[i].r) move(++r,1);
while(r>q[i].r) move(r--,-1);
ans[q[i].pos]=query(q[i].y)-query(q[i].x-1);
}
for(rg int i=1;i<=m;i++) printf("%d
",ans[i]);
return 0;
}