What comes after, tiny fractures!|

落花月朦胧

园龄:3年6个月粉丝:14关注:10

分块和普通莫队入门

分块

分块是一种数据结构,其核心就是暴力。和线段树和树状数组一样,它可以支持区间修改,单点修改,区间查询,单点查询。
总体来讲,可以总结为大段维护,小段暴力。
下面具体讲一下它的实施。
首先,我们了一个数组,假设这个数组的大小是 n,那么我们就把它分成 n 段,其中 n 段的大小都是 n,剩下最后一个段的大小就是 nn×n
就像下面这张图一样。(画的太丑乐)

image

分块基本上都可以做到线段树能做的,所以就拿线段树的板子来写一下。

P3372 【模板】线段树 1
对于每一个段,我们可以单独维护两个数组,一个表示这个段里面的和,另一个表示这个块的延迟标记。
我们可以把 [l,r] 这个区间看成这样子。
image

  • 查询:
    那么橙色部分就可以直接维护,让我们的答案直接加上这段的和以及延迟标记乘上块长即可。
    而对于我用绿色圈出来的部分就没有办法了,只能暴力算了。
  • 修改
    一样的,对于橙色部分,我们直接让这一段的延迟标记直接加。
    而绿色部分也暴力维护即可。

然后为了方便写,可以维护一些东西,比如这个块是哪一个区间,大小是多少,所有下标所归属的块的标号等等。

时间复杂度为 O(nn)

int n, m;
i64 a[N], sum[N], add[N], z;
int l[N], r[N], belong[N], siz[N];
int op, x, y;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
std::cin >> n >> m;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
int k = std::sqrt(n), kn = 1;
for (int i = 1; ; i += k, kn++) {
if (i + k - 1 >= n) {
l[kn] = i;
r[kn] = n;
break;
} else {
l[kn] = i;
r[kn] = i + k - 1;
}
}
for (int i = 1; i <= kn; i++) {
for (int j = l[i]; j <= r[i]; j++) {
sum[i] += a[j];
belong[j] = i;
}
siz[i] = r[i] - l[i] + 1;
}
while (m--) {
std::cin >> op >> x >> y;
if (op == 1) {
std::cin >> z;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) {
a[i] += z;
sum[belong[x]] += z;
}
} else {
for (int i = x; i <= r[belong[x]]; i++) {
a[i] += z;
sum[belong[x]] += z;
}
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) {
add[i] += z;
}
for (int i = l[belong[y]]; i <= y; i++) {
a[i] += z;
sum[belong[y]] += z;
}
}
} else {
i64 ans = 0;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) {
ans += a[i] + add[belong[x]];
}
} else {
for (int i = x; i <= r[belong[x]]; i++) {
ans += a[i] + add[belong[x]];
}
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) {
ans += sum[i] + add[i] * siz[i];
}
for (int i = l[belong[y]]; i <= y; i++) {
ans += a[i] + add[belong[y]];
}
}
std::cout << ans << "\n";
}
}
return 0;
}

莫队

莫队就是一个离线处理多个询问的算法,因为是离线的,所以普通的莫队不支持修改。然后莫队算法最精髓的东西就是它对询问进行分块。

首先把询问给读入进来,按照字典序排一下序,然后根据这个询问的区间一步一步的拓展区域,这就是莫队的最精髓的东西。然后如果这个拓展的过程可以 O(1),那么时间复杂度就是 O(nn),这个东西 OI-Wiki 上有证明,但是我咕咕咕。

然后就是一个拓展区域的问题,应该怎么拓展就是一个问题。

image

OI-Wiki 写的很好,所以我就不写了,这个背一个形式应该就可以吧,我觉得背 l--, r++, l++, r-- 就很好。

P1494 [国家集训队] 小 Z 的袜子

这个题还要用一点排列组合:

但是先咕咕咕者。

好,莫队咕完了。

本文作者:Falling-flowers 的 blog

本文链接:https://www.cnblogs.com/falling-flowers/p/17454219.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   落花月朦胧  阅读(45)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起