『算法-ACM竞赛』莫队算法

『算法-ACM 竞赛』莫队算法

莫队算法可以一个可高效解决绝大多数离线+无修改+区间查询问题的算法。这类问题具体是指:如果知道[L,R]的答案时,可以在 O(g(n))的时间下得到[L,R−1],[L,R+1],[L−1,R],[L+1,R]的答案的话,就可以$O(n\sqrt n · \mathrm{g}(n))$的时间内求出所有查询。

假设我们算完[L,R]的答案后现在要算[L′,R′]的答案。由于可以在 O(1)的时间下得到[L,R−1],[L,R+1],[L−1,R],[L+1,R]的答案,所以计算[L′,R′]的答案耗时|L−L′|+|R−R′|。如果把询问[L,R]看做平面上的点 a(L,R),询问[L′,R′]看做点 b(L′,R′)的话,那么时间开销就为两点的曼哈顿距离。

具体实现
我们先对序列分块,每块长度为 sqrt(n),然后以询问左端点所在的块为第一关键字,右端点的大小为第二关键字进行排序
然后每个区间由它的上一个区间推出来,虽然单次询问仍可能是 O(n),
但是在块中每次询问 l 的移动最大为 sqrt(n),r 的移动总和最大为 n,块与块之间的移动最大为 n
所以总复杂度为 O((n+m)sqrt(n))

我这里给出莫队的模板,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 50010
#define LL long long
using namespace std;
int n, m, k, unit;
struct Mo
{
int l;
int r;
int id;
int pos;
bool operator<(const Mo &rhs) const
{
if (pos == rhs.pos)
return r < rhs.r;
else
return l < rhs.l;
}
} a[N];
int b[N], cnt[N];
LL Ans[N];
int main()
{
scanf("%d%d%d", &n, &m, &k);
unit = sqrt(n + 1);
for (int i = 1; i <= n; i++)
scanf("%d", &b[i]);
for (int i = 1; i <= m; i++)
{
scanf("%d%d", &a[i].l, &a[i].r);
a[i].id = i;
a[i].pos = a[i].l / unit;
}
sort(a + 1, a + 1 + m);
int l = 1, r = 0;
LL ans = 0;
for (int i = 1; i <= m; i++)
{
while (l > a[i].l)
{
l--;
//操作
ans +=
}
while (r < a[i].r)
{
r++;
//操作
ans +=
}
while (l < a[i].l)
{
ans -=
//操作
l++;
}
while (r > a[i].r)
{
ans -=
//操作
r--;
}
Ans[a[i].id] = ans;
}
for (int i = 1; i <= m; i++)
printf("%lld\n", Ans[i]);
return 0;
}
1


『算法-ACM竞赛』莫队算法
https://chiamzhang.github.io/2024/06/29/『算法-ACM竞赛』莫队算法/
Author
Chiam
Posted on
June 29, 2024
Licensed under