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 }

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

时间: 2024-10-09 07:20:06

P2709 小B的询问 【普通莫队】的相关文章

3781. 小B的询问【莫队】

Description 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. Input 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. Output M行,每行一个整数,其中第i行的整数表示第i个询问的答案. Sample Input 6 4 3 1 3 2 1 1 3 1

【BZOJ】3781: 小B的询问(莫队算法)

http://www.lydsy.com/JudgeOnline/problem.php?id=3781 还能不能再裸点.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> #include <set>

[luoguP2709] 小B的询问(莫队)

传送门 个数 1 2 3 4 5 答案 1 4 9  16 25 做差 1 3 5 7 9 显然增加一个数只需要增加 ton[a[x]] << 1 | 1 即可 减去一个数也减去这个 注意先加减再更新 ton ——代码 1 #include <cmath> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 6 const int MAXN = 50001; 7 i

P2709 小B的询问 莫队

这个题,莫队很容易想到(格式很明显),然后直接用数学公式维护一下和就行了. 题干: 题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第

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

入门题 对于一个区间的询问,如果在已知\([l,r]\)的答案时可以用O(1)的时间求出左右端点\(±1\)的答案,就可以使用莫队来优化. 设已知区间为\([l_1,r_1]\),所求区间为\([l_2,r_2]\) 可知求得\([l_2,r_2]\)的成本是\(|l_1-l_2| + |r_1-r_2|\)如果把这两个区间看成点,这个成本就是两点的曼哈顿距离, 对于多个询问,求出曼哈顿距离最小生成树就可以以最小成本获得答案,使用一种奇怪的方式 --sort来获得最优的转移方式 我并不知道原理

洛谷 P2709 小B的询问

https://www.luogu.org/problem/show?pid=2709 题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表

bzoj2038: [2009国家集训队]小Z的袜子(hose) [莫队]

Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬.你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子.当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择

BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )

莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) ------------------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50009; int N,

bzoj 2038 [2009国家集训队]小Z的袜子(hose) 莫队算法

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 10239  Solved: 4659[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命--具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两