神奇莫队学习笔记
0x282e202e2029 · · 算法·理论
莫队算法是解决一类离线区间询问问题的分块算法。
形式
莫队算法主要用于解决单点调整操作较易的离线区间询问问题。形式化地,从
排序方法
记序列总长为
对于区间
时间复杂度
以下设单点调整操作时间复杂度为
-
排序,此处时间复杂度
O(n \log n) ; -
指针调整完毕整块的时间复杂度为
O(xB) (x 为此块内部左端点个数),此处时间复杂度O(qB) ; -
因为左端点同块的区间右端点有序,所以在同一块内部,右端点最劣要
O(n) 次调整(即调整整个序列),共\displaystyle \frac{n}{B} 个块,此次时间复杂度\displaystyle O(\frac{n^2}{B}) 。
共
例题 P1972(60 pts 非正解)
// initalize blocks
int B, Bcnt, b[1001005];
void init() {
B = sqrt(n), Bcnt = ceil((double) n / B);
for (int i = 1; i <= Bcnt; ++i) {
for (int j = (i - 1) * B + 1; j <= i * B; ++j) {
b[j] = i;
}
}
}
// sort queries
struct Query {
int l, r, id;
} q[1000005];
bool operator < (Query x, Query y) {
return (b[x.l] ^ b[y.l]) ? b[x.l] < b[y.l] : ((b[x.l] & 1) ? x.r < y.r : x.r > y.r);
}
// solve queries
int cnt[1000005] = {}, tot = 0, ans[1000005];
void solve() {
int l = 1, r = 0, ql, qr;
for (int i = 1; i <= m; ++i) {
ql = q[i].l, qr = q[i].r;
while (l < ql) tot -= !--cnt[a[l++]];// del l
while (l > ql) tot += !cnt[a[--l]]++;// add l
while (r < qr) tot += !cnt[a[++r]]++;// add r
while (r > qr) tot -= !--cnt[a[r--]];// del r
ans[q[i].id] = tot;
}
}