P2709 小B的询问 普通莫队

Posted yuanweidao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2709 小B的询问 普通莫队相关的知识,希望对你有一定的参考价值。

这是我的莫队入门题,我也了解到了莫队分为普通莫队以及带修莫队。顾名思义,普通莫队不需要修改区间的值,而带修莫队处理区间的值会修改的查询。

能用莫队的前提条件

1.在知道 【l, r】中信息时,可以在 O(1)的复杂度内知道 【l - 1, r】,【l + 1, r】,【l, r - 1】,【l, r + 1】的信息,否则复杂度会爆炸。

2.能离线处理。

莫队的时间复杂度为O(n ^ 1.5),但实际效果一定会优于这个时间复杂度。

莫队的主要操作:

1.对查询区间,以 left 来进行分块,然后将分块作为第一关键字来进行从小到大的排序,以right为第二关键字来进行从小到大的排序

2.找到区间之间的转移方程,边查询边修改。

题目链接:https://www.luogu.org/problemnew/show/P2709

思路:

1.莫队的模板题。

2.值得注意的是扩充区间时,先动指针,再修改值。缩小区间时,先修改值,再动指针。这样做是为了保证区间一定有长度。

代码如下:

技术图片
 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<math.h>
 4 #include<string.h>
 5 #define mem(a, b) memset(a, b, sizeof(a))
 6 using namespace std;
 7 
 8 int n, m, k;
 9 int num[50010];
10 long long cnt[50010];
11 long long ANS[50010];
12 
13 struct Query
14 
15     int l, r, id;
16     int pos;
17 q[50010];
18 
19 bool cmp(Query a, Query b)
20 
21     if(a.pos != b.pos)
22         return a.pos < b.pos; //第1关键字是块 
23     else
24         return a.r < b.r;  //第2关键字是右边界 
25 
26 
27 int main()
28 
29     scanf("%d%d%d", &n, &m, &k);
30     mem(cnt, 0);
31     for(int i = 1; i <= n; i ++)
32         scanf("%d", &num[i]);
33     int fk = sqrt(n);
34     for(int i = 1; i <= m; i ++)  //莫队要离线处理
35     
36         scanf("%d%d", &q[i].l, &q[i].r);
37         q[i].id = i;
38         q[i].pos = (q[i].l - 1) / fk + 1;
39     
40     sort(q + 1, q + 1 + m, cmp);
41     int L = 1, R = 0;
42     long long ans = 0;
43     for(int i = 1; i <= m; i ++)
44     
45         while(L > q[i].l)//扩充 
46         
47             L --;
48             cnt[num[L]] ++;
49             ans += 2 * cnt[num[L]] - 1;
50         
51         while(R < q[i].r) //扩充
52         
53             R ++;
54             cnt[num[R]] ++;
55             ans += 2 * cnt[num[R]] - 1;
56         
57         while(L < q[i].l)//缩小 
58         
59             cnt[num[L]] --;
60             ans -= 2 * cnt[num[L]] + 1;
61             L ++;
62         
63         while(R > q[i].r)//缩小 
64         
65             cnt[num[R]] --;
66             ans -= 2 * cnt[num[R]] + 1;
67             R --;
68         
69         ANS[q[i].id] = ans;
70     
71     for(int i = 1; i <= m; i ++)
72     
73         printf("%lld\n", ANS[i]);
74     
75     return 0;
76 
View Code

 

以上是关于P2709 小B的询问 普通莫队的主要内容,如果未能解决你的问题,请参考以下文章

P2709 小B的询问 莫队算法

[BZOJ3781][P2709]小B的询问[莫队]

P2709 小B的询问

luogu P2709 小B的询问

P2709 小B的询问

P2709 小B的询问