题意
给定序列 (a),多次询问:
- (a[l..r]) 有多少数在 ([a..b]) 中;
- (a[l..r]) 有多少数在 ([a..b]) 中(去重)。
(n,mleq 10^5)
题解
莫队显然。每次移动指针时要单点修改((O(nsqrt n)) 次),查询时查询区间和((O(n)) 次)。用分块实现 (O(1)) 修改、(O(sqrt n)) 查询,复杂度为 (O(nsqrt n))。
#include<bits/stdc++.h>
using namespace std;
const int BUF_LEN=1<<19;
struct FastIO{
char bufi[BUF_LEN+10],*PTi=bufi+BUF_LEN,*PTENDi=bufi+BUF_LEN;
inline char gc(){
(PTi==PTENDi)&&(bufi[fread(bufi,1,BUF_LEN,stdin)]=0,PTi=bufi);
return *(PTi++);
}
char bufo[BUF_LEN+10],*PTo=bufo,*PTENDo=bufo+BUF_LEN;
inline void pc(char c){
(PTo==PTENDo)&&(fwrite(bufo,1,BUF_LEN,stdout),PTo=bufo);
*(PTo++)=c;
}
void flush(){
fwrite(bufo,1,PTo-bufo,stdout);
PTo=bufo;
}
~FastIO(){
flush();
}
template<class T>inline void getint(T &x=0){
char c=gc();
int f=1;x=0;
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=gc();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=gc();
}
if(f==-1)x=-x;
}
operator int(){
int v;getint(v);return v;
}
operator long long(){
long long v;getint(v);return v;
}
template<class T>inline void putint(T x=0,char sep=' '){
char tmp[20],len=0;
if(x<0)pc('-'),x=-x;
if(x==0){ pc('0');pc(sep);return; }
while(x)tmp[len++]=x%10,x/=10;
for(int i=len-1;~i;--i)pc(tmp[i]|'0');
pc(sep);
}
}io;
const int N=1e5+10,M=1e6+10,Q=1010;
struct Block_div{
int blk;
int s[Q],a[N];
void modify(int x,int y){ s[x/blk]+=y,a[x]+=y; }
int query(int r){
int ans=0;
int i=blk-1;
for(int j=0;i<=r;i+=blk,j++)ans+=s[j];
for(i-=blk-1;i<=r;i++)ans+=a[i];
return ans;
}
};
Block_div s,uni;
int n,m;
int a[N];
int blk,bl[N];
struct Query{
int l,r,a,b,num;
}q[M];
bool cmp(const Query &a,const Query &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;
}
int ans1[M],ans2[M];
int main(){
n=io,m=io;
blk=max(n/sqrt(m*0.8),1.0);
s.blk=uni.blk=sqrt(n);
for(int i=1;i<=n;i++)a[i]=io;
for(int i=1;i<=n;i++)bl[i]=i/blk;
for(int i=0;i<m;i++)q[i].l=io,q[i].r=io,q[i].a=io,q[i].b=io,q[i].num=i;
sort(q,q+m,cmp);
int l=2,r=1;
for(int i=0;i<m;i++){
while(l<q[i].l){
s.modify(a[l],-1);
if(!s.a[a[l]])uni.modify(a[l],-1);
++l;
}
while(r>q[i].r){
s.modify(a[r],-1);
if(!s.a[a[r]])uni.modify(a[r],-1);
--r;
}
while(l>q[i].l){
--l;
if(!s.a[a[l]])uni.modify(a[l],1);
s.modify(a[l],1);
}
while(r<q[i].r){
++r;
if(!s.a[a[r]])uni.modify(a[r],1);
s.modify(a[r],1);
}
ans1[q[i].num]=s.query(q[i].b)-s.query(q[i].a-1);
ans2[q[i].num]=uni.query(q[i].b)-uni.query(q[i].a-1);
}
for(int i=0;i<m;i++)io.putint(ans1[i],' '),io.putint(ans2[i],'
');
}