码迷,mamicode.com
首页 > 其他好文 > 详细

P2709 小B的询问 【普通莫队】

时间:2019-06-06 21:09:20      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:图片   hid   修改   转移   lap   指针   names   scanf   blank   

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

能用莫队的前提条件

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的询问 【普通莫队】

标签:图片   hid   修改   转移   lap   指针   names   scanf   blank   

原文地址:https://www.cnblogs.com/yuanweidao/p/10986682.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!