【bzoj3809】Gty的二逼妹子序列

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。
建议使用输入/输出优化。
 
该题要求什么题目已经说得很清楚了。。。
把这个题再打一遍只不过是想在温习一下莫队算法还记不记得。。。
莫队算法果然是深入OIER的人心啊,感天动地我竟然还会打(不会打莫队真是愧对CJ前辈啊);
这个题的思想很巧妙。。。这题如果用树状数组来实现的话可以实现logn的转移和查询可以获得60分。。。
这个题的巧妙之处就是对值域进行分块!!!
这样的话莫队l和r指针移动时的转移是O(1)的,而每个询问的查询是sqrt(n)的;
查询的话还是用分快查询的常见套路,整块的直接加,不是整块的就暴力搞。。。
而出现次数的话开一个桶就可以实现了,类似HH的项链。。。
一开始l[i]成(i-1)*block了,忘了加1。。。。
附上代码:
 1 // MADE BY QT666
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<queue>
 7 #include<set>
 8 #include<cstdlib>
 9 #include<cstring>
10 #include<string>
11 #include<ctime>
12 #define lson num<<1
13 #define rson num<<1|1
14 using namespace std;
15 typedef long long ll;
16 const int N=100050;
17 const int M=1000050;
18 int gi()
19 {
20   int x=0,flag=1;
21   char ch=getchar();
22   while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
23   while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
24   return x*flag;
25 }
26 int n,m,a[N],block,pos[N],blockans[N],l[N],r[N],cnt,ans[M],tong[N];
27 struct ac
28 {
29     int l,r,L,R,id;
30 }q[M];
31 bool cmp(const ac &a,const ac &b)
32 {
33   if(pos[a.l]==pos[b.l]) return a.r<b.r;
34   return pos[a.l]<pos[b.l];
35 }
36 void pre()
37 {
38     for(int i=1;i<=cnt;i++) l[i]=(i-1)*block+1,r[i]=i*block;
39     r[cnt]=n;
40     for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
41 }
42 void update(int x,int val) {tong[x]+=val;}
43 int query(int x,int y)
44 {
45     int sum=0;
46     if(pos[x]==pos[y])
47       {
48           for(int i=x;i<=y;i++) if(tong[i]) sum++;
49       }
50     else
51       {
52           for(int i=x;i<=r[pos[x]];i++) if(tong[i]) sum++;
53           for(int i=l[pos[y]];i<=y;i++) if(tong[i]) sum++;
54           for(int i=pos[x]+1;i<=pos[y]-1;i++) sum+=blockans[i];
55       }
56     return sum;
57 }
58 void work()
59 {
60     for(int i=1,l=1,r=0;i<=m;i++)
61         {
62             while(l>q[i].l) {l--;update(a[l],1);if(tong[a[l]]==1) blockans[pos[a[l]]]++;}
63             while(r<q[i].r) {r++;update(a[r],1);if(tong[a[r]]==1) blockans[pos[a[r]]]++;}
64             while(l<q[i].l) {update(a[l],-1);if(tong[a[l]]==0) blockans[pos[a[l]]]--;l++;}
65             while(r>q[i].r) {update(a[r],-1);if(tong[a[r]]==0) blockans[pos[a[r]]]--;r--;}
66             ans[q[i].id]=query(q[i].L,q[i].R);
67         }
68 }
69 int main()
70 {
71     n=gi(),m=gi();
72     for(int i=1;i<=n;i++) a[i]=gi();
73     for(int i=1;i<=m;i++) q[i].l=gi(),q[i].r=gi(),q[i].L=gi(),q[i].R=gi(),q[i].id=i;
74     block=(int)sqrt(n);
75     if(n%block==0) cnt=n/block;
76     else cnt=n/block+1;
77     pre();
78     sort(q+1,q+1+m,cmp);
79     work();
80     for(int i=1;i<=m;i++) printf("%d
",ans[i]);
81     return 0;
82 }
 
原文地址:https://www.cnblogs.com/qt666/p/6491699.html