P4688 [Ynoi2016]掉进兔子洞

P4688 [Ynoi2016]掉进兔子洞

https://www.luogu.org/problemnew/show/P4688

 

分析:

  莫队+bitset。

  一个询问的答案就是 (r1-l1+1) + (r2-l2+1) + (r3-l3+1) - 三个区间都有的元素的个数。

  前面一块可以直接求,后面的考虑莫队。我们可以用bitset来实现查询三个区间都出现的个数。但是每个区间内不保证数字都不一样,如果出现了相同的数字,可以依次在bitset中排开,例如12223,在bitset中的坐标就是12345,所以在离散化的时候只要不去重就行了,然后在增加删除一个数的时候,这个数的位置就是离散化后的坐标+前面有多少相同的数。注意,区间的位置移动的时候,要先加再减,如果先减,可能先使cnt变成了负数,然后再变成正数,那么birset可能访问无效内存,从而使得RE。

  然后发现空间可能会MLE,于是考虑分块处理询问,每个处理询问25000个,然后处理4次。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #include<bitset>
12 using namespace std;
13 typedef long long LL;
14 
15 inline int read() {
16     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
17     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
18 }
19 
20 const int N = 100000;
21 const int T = 25000;
22 
23 int a[N + 5], b[N + 5], bel[N + 5], cnt[N + 5], ans[T + 5];
24 bool vis[T + 5];
25 bitset<N + 5> f[T + 5], g;
26 
27 struct Que{
28     int l, r, id;
29 }q[T * 3 + 5];
30 
31 bool cmp(Que A, Que B) {
32     if (bel[A.l] == bel[B.l]) return A.r < B.r;
33     return bel[A.l] < bel[B.l];
34 }
35 void add(int p) {
36     int x = a[p];
37     cnt[x] ++;
38     g[x + cnt[x] - 1] = 1;
39 }
40 void del(int p) {
41     int x = a[p];
42     g[x + cnt[x] - 1] = 0;
43     cnt[x] --;
44 }
45 void solve(int m) {
46     memset(vis, false, sizeof(vis));
47     memset(ans, 0, sizeof(ans));
48     memset(cnt, 0, sizeof(cnt));
49     int n = 0;
50     for (int i=1; i<=m; ++i) {
51         q[++n].id = i, q[n].l = read(), q[n].r = read(); 
52         ans[i] += q[n].r - q[n].l + 1;
53         
54         q[++n].id = i, q[n].l = read(), q[n].r = read();
55         ans[i] += q[n].r - q[n].l + 1;
56         
57         q[++n].id = i, q[n].l = read(), q[n].r = read();
58         ans[i] += q[n].r - q[n].l + 1;
59     }
60     sort(q + 1, q + n + 1, cmp);
61     g.reset();
62     int L = 1, R = 0;
63     for (int i=1; i<=n; ++i) {
64         // 让add在前,如果del在前,可能会使cnt变成负数,使bitset访问无效内存,RE 
65         while (L > q[i].l) add(--L); 
66         while (R < q[i].r) add(++R);
67         while (L < q[i].l) del(L++);
68         while (R > q[i].r) del(R--);
69         if (!vis[q[i].id]) f[q[i].id] = g, vis[q[i].id] = 1;
70         else f[q[i].id] &= g;
71     }
72     for (int i=1; i<=m; ++i) {
73         ans[i] -= f[i].count() * 3;
74         printf("%d\n",ans[i]);
75     }
76 }
77 int main() {
78     int n = read(), m = read();
79     int B = sqrt(n);
80 
81     for (int i=1; i<=n; ++i) a[i] = read(), b[i] = a[i], bel[i] = (i - 1) / B + 1;
82     sort(b + 1, b + n + 1);
83     for (int i=1; i<=n; ++i) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
84     
85     while (m) {
86         if (m < T) solve(m), m = 0;
87         else solve(T), m -= T;
88     }
89     return 0;
90 }

 

posted @ 2018-09-11 10:40  MJT12044  阅读(459)  评论(0编辑  收藏  举报