分块和普通莫队入门
分块
分块是一种数据结构,其核心就是暴力。和线段树和树状数组一样,它可以支持区间修改,单点修改,区间查询,单点查询。
总体来讲,可以总结为大段维护,小段暴力。
下面具体讲一下它的实施。
首先,我们了一个数组,假设这个数组的大小是 ,那么我们就把它分成 段,其中 段的大小都是 ,剩下最后一个段的大小就是 。
就像下面这张图一样。(画的太丑乐)
分块基本上都可以做到线段树能做的,所以就拿线段树的板子来写一下。
P3372 【模板】线段树 1
对于每一个段,我们可以单独维护两个数组,一个表示这个段里面的和,另一个表示这个块的延迟标记。
我们可以把 这个区间看成这样子。
- 查询:
那么橙色部分就可以直接维护,让我们的答案直接加上这段的和以及延迟标记乘上块长即可。
而对于我用绿色圈出来的部分就没有办法了,只能暴力算了。 - 修改
一样的,对于橙色部分,我们直接让这一段的延迟标记直接加。
而绿色部分也暴力维护即可。
然后为了方便写,可以维护一些东西,比如这个块是哪一个区间,大小是多少,所有下标所归属的块的标号等等。
时间复杂度为
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; }
莫队
莫队就是一个离线处理多个询问的算法,因为是离线的,所以普通的莫队不支持修改。然后莫队算法最精髓的东西就是它对询问进行分块。
首先把询问给读入进来,按照字典序排一下序,然后根据这个询问的区间一步一步的拓展区域,这就是莫队的最精髓的东西。然后如果这个拓展的过程可以 ,那么时间复杂度就是 ,这个东西 OI-Wiki 上有证明,但是我咕咕咕。
然后就是一个拓展区域的问题,应该怎么拓展就是一个问题。
OI-Wiki 写的很好,所以我就不写了,这个背一个形式应该就可以吧,我觉得背 l--, r++, l++, r--
就很好。
这个题还要用一点排列组合:
但是先咕咕咕者。
好,莫队咕完了。
本文作者:Falling-flowers 的 blog
本文链接:https://www.cnblogs.com/falling-flowers/p/17454219.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步