[BZOJ3809]Gty的二逼妹子序列
题目大意:
给定一个长度为$n(n\leq10^5)$的数列,$m(m\leq10^6)$组询问,每次求出$A_{l..r}$中,权值$\in[a,b]$的权值的种类数。
思路:
莫队处理询问,分块维护每个区间内的权值种类数。时间复杂度$O(m\sqrt n)$。如果用树状数组是$O(m\sqrt n\log n)$的,会TLE。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=100001,M=1000000; 13 int v[N],ans[M],cnt[N],sum[N],n,block,bel[N],begin[N],end[N]; 14 struct Query { 15 int l,r,a,b,id; 16 bool operator < (const Query &another) const { 17 return l/block<another.l/block||(l/block==another.l/block&&r/block<another.r/block); 18 } 19 }; 20 Query q[M]; 21 inline void ins(const int &x) { 22 if(!cnt[v[x]]++) sum[bel[v[x]]]++; 23 } 24 inline void del(const int &x) { 25 if(!--cnt[v[x]]) sum[bel[v[x]]]--; 26 } 27 inline int query(const int &l,const int &r) { 28 int ret=0; 29 if(bel[l]==bel[r]) { 30 for(register int i=l;i<=r;i++) ret+=(bool)cnt[i]; 31 return ret; 32 } 33 for(register int i=l;bel[i]==bel[l];i++) ret+=(bool)cnt[i]; 34 for(register int i=r;bel[i]==bel[r];i--) ret+=(bool)cnt[i]; 35 for(register int i=bel[l]+1;i<bel[r];i++) ret+=sum[i]; 36 return ret; 37 } 38 int main() { 39 block=sqrt(n=getint()); 40 const int m=getint(); 41 for(register int i=1;i<=n;i++) { 42 v[i]=getint(); 43 bel[i]=i/block; 44 if(!begin[bel[i]]) begin[bel[i]]=i; 45 end[bel[i]]=i; 46 } 47 for(register int i=0;i<m;i++) { 48 const int l=getint(),r=getint(),a=getint(),b=getint(); 49 q[i]=(Query){l,r,a,b,i}; 50 } 51 std::sort(&q[0],&q[m]); 52 for(register int i=0,l=1,r=0;i<m;i++) { 53 while(r<q[i].r) ins(++r); 54 while(l>q[i].l) ins(--l); 55 while(r>q[i].r) del(r--); 56 while(l<q[i].l) del(l++); 57 ans[q[i].id]=query(q[i].a,q[i].b); 58 } 59 for(register int i=0;i<m;i++) printf("%d\n",ans[i]); 60 return 0; 61 }