Bzoj 3809: Gty的二逼妹子序列 莫队,分块

3809: Gty的二逼妹子序列

Time Limit: 35 Sec  Memory Limit: 28 MB
Submit: 868  Solved: 234
[Submit][Status][Discuss]

Description

Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
 
对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
 
为了方便,我们规定妹子们的美丽度全都在[1,n]中。
 
给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl...sr中,权值∈[a,b]的权值的种类数。

Input

第一行包括两个整数n,m(1<=n<=100000,1<=m<=1000000),表示数列s中的元素数和询问数。
 
第二行包括n个整数s1...sn(1<=si<=n)。
 
接下来m行,每行包括4个整数l,r,a,b(1<=l<=r<=n,1<=a<=b<=n),意义见题目描述。
 
保证涉及的所有数在C++的int内。
 
保证输入合法。

Output

对每个询问,单独输出一行,表示sl...sr中权值∈[a,b]的权值的种类数。

Sample Input

10 10
4 4 5 1 4 1 5 1 2 1
5 9 1 2
3 4 7 9
4 4 2 5
2 3 4 7
5 10 4 4
3 9 1 1
1 4 5 9
8 9 3 3
2 2 1 6
8 9 1 4

Sample Output

2
0
0
2
1
1
1
0
1
2

HINT

样例的部分解释:

 

5 9 1 2

子序列为4 1 5 1 2

在[1,2]里的权值有1,1,2,有2种,因此答案为2。

 

3 4 7 9

子序列为5 1

在[7,9]里的权值有5,有1种,因此答案为1。

 

4 4 2 5

子序列为1

没有权值在[2,5]中的,因此答案为0。

 

2 3 4 7

子序列为4 5

权值在[4,7]中的有4,5,因此答案为2。

 

建议使用输入/输出优化。

Source

 题解:
直接莫队加分块。(将颜色进行分块即可)
代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define MAXN 100010
 4 #define MAXM 1000010
 5 struct node
 6 {
 7     int l,r,a,b,id;
 8 }q[MAXM];
 9 int tot[MAXN],sum[336],pos[MAXN],C[MAXN],block,ans[MAXM];
10 int read()
11 {
12     int s=0,fh=1;char ch=getchar();
13     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
14     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
15     return s*fh;
16 }
17 bool cmp(node aa,node bb)
18 {
19     if(pos[aa.l]==pos[bb.l])return aa.r<bb.r;
20     return aa.l<bb.l;
21 }
22 void Del(int color)//删除一种颜色
23 {
24     tot[color]--;//该种颜色个数-1.
25     if(tot[color]==0)sum[(color-1)/block+1]--;//以前有的颜色,现在没有了.(个数从1变为0.)
26 }
27 void Add(int color)//加上一种颜色
28 {
29     tot[color]++;//该种颜色个数+1.
30     if(tot[color]==1)sum[(color-1)/block+1]++;//以前没有的颜色,现在有了.(个数从0变为1.)
31 }
32 int getans(int aa,int bb)
33 {
34     int gs=0,left=(aa-1)/block+1,right=(bb-1)/block+1,i;
35     if(left==right)
36     {
37         for(i=aa;i<=bb;i++)if(tot[i]!=0)gs++;
38         return gs;
39     }
40     for(i=aa;i<=left*block;i++)if(tot[i]!=0)gs++;
41     for(i=left+1;i<=right-1;i++)gs+=sum[i];
42     for(i=(right-1)*block+1;i<=bb;i++)if(tot[i]!=0)gs++;
43     return gs;
44 }
45 int main()
46 {
47     int n,m,i,L,R;
48     n=read();m=read();
49     for(i=1;i<=n;i++)C[i]=read();
50     for(i=1;i<=m;i++)
51     {
52         q[i].l=read();q[i].r=read();q[i].a=read();q[i].b=read();
53         q[i].id=i;
54     }
55     block=(int)sqrt(n);
56     for(i=1;i<=n;i++)pos[i]=(i-1)/block+1;
57     sort(q+1,q+m+1,cmp);
58     memset(sum,0,sizeof(sum));//每一块内的颜色个数.
59     memset(tot,0,sizeof(tot));//枚举的区间内的每种颜色的个数.
60     L=1;R=0;
61     for(i=1;i<=m;i++)
62     {
63         while(L<q[i].l)
64         {
65             Del(C[L]);
66             L++;
67         }
68         while(L>q[i].l)
69         {
70             L--;
71             Add(C[L]);
72         }
73         while(R<q[i].r)
74         {
75             R++;
76             Add(C[R]);
77         }
78         while(R>q[i].r)
79         {
80             Del(C[R]);
81             R--;
82         }
83         ans[q[i].id]=getans(q[i].a,q[i].b);
84     }
85     for(i=1;i<=m;i++)printf("%d
",ans[i]);
86     fclose(stdin);
87     fclose(stdout);
88     return 0;
89 }
View Code
原文地址:https://www.cnblogs.com/Var123/p/5278676.html