[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 }

 

posted @ 2018-03-07 18:05  skylee03  阅读(113)  评论(0编辑  收藏  举报