莫队

news/发布时间2024/5/19 9:06:24

简介

莫队是一种离线求区间信息的算法,可以做到 \(O((N+Q) \cdot\sqrt{N})\)。莫队中使用了分块的思想。

首先考虑一个问题:给定一个长度为 \(N\) 序列 \(A\)\(Q\) 次询问,每次询问查询区间 \([X_i,Y_i]\) 的和。(请先忘掉前缀和、线段树、树状数组什么的)

比如以下数据:

5 4
3 2 2 1 5
1 3
4 5
2 6
1 1
2 2

莫队的思想是:记录一个 \(l,r\)\(sum\),其中 \(sum=\sum \limits_{i=l}^r A_i\)。每次求一个新区间时,不断移动 \(l,r\),并维护 \(sum\)

如:

int l = 1, r = 0, sum = 0, x, y;cin >> x >> y;
for(; l > x; sum += a[--l]) {
}
for(; r < y; sum += a[++r]) {
}
for(; l < x; sum -= a[l++]) {
}
for(; r > y; sum -= a[r--]) {
}
cout << sum << "\n";

可这样仍然是 \(O(N)\) 的。

所以,我们可以离线求解。我们可以对查询区间按某种方式排序,使得时间复杂度更优。而莫队的排序策略是这样的:

  • 如果 \(\lfloor \frac{X_i}{\sqrt N} \rfloor = \lfloor \frac{X_j}{\sqrt N} \rfloor\)
    • 如果 \(Y_i < Y_j\),那么排序后 \(i\) 放在 \(j\) 前面。
    • 否则排序后 \(j\) 放在 \(i\) 前面。
  • 如果 \(\lfloor \frac{X_i}{\sqrt N} \rfloor \ne \lfloor \frac{X_j}{\sqrt N} \rfloor\)
    • 如果 \(\lfloor \frac{X_i}{\sqrt N} \rfloor <\lfloor \frac{X_j}{\sqrt N} \rfloor\),那么排序后 \(i\) 放在 \(j\) 前面。
    • 否则排序后 \(j\) 放在 \(i\) 前面。

按照这样的方式排序,那么 \(l\) 在一个块中会移动 \(O(Q)\) 次,共移动 \(O(Q\cdot\sqrt N)\)
次,右端点在同一个块中都是递增的,所以在一个块中移动 \(O(N)\) 次,共移动 \(O(N \cdot \sqrt N)\) 次。总时间复杂度 \(O((N+Q) \cdot \sqrt N)\)

莫队不仅能求解区间和,很多其他区间信息也能求解。

优化

可以发现,每次处理完一个块后,右端点都要从新移动回去,所以我们可以让所有偶数块右端点从小到大,奇数块从大到小,可以优化大约 \(\frac{1}{2}\) 的常数。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;const int MAXN = 200001, MAXS = 447, MAXQ = 200001;struct Node {int l, r, id;
}s[MAXQ];int n, q, a[MAXN];
ll sum, ans[MAXQ];int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);cin >> n >> q;for(int i = 1; i <= n; ++i) {cin >> a[i];}for(int i = 1; i <= q; ++i) {cin >> s[i].l >> s[i].r;s[i].id = i;}sort(s + 1, s + q + 1, [](const Node &a, const Node &b) { return (a.l / MAXS == b.l / MAXS ? (a.l / MAXS % 2 ? a.r > b.r : a.r < b.r) : a.l / MAXS < b.l / MAXS); });ll sum = 0;for(int i = 1, x = 1, y = 0; i <= q; ++i) {for(; x > s[i].l; sum += a[--x]) {}for(; y < s[i].r; sum += a[++y]) {}for(; x < s[i].l; sum -= a[x++]) {}for(; y > s[i].r; sum -= a[y--]) {}ans[s[i].id] = sum;}for(int i = 1; i <= q; ++i) {cout << ans[i] << "\n";}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/68874261.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

找win电脑代理地址

1.进入控制面板2.Internet属性3.局域网设置

Ubuntu部署有道QAnything(中间涉及到更换mysql容器端口)

系统配置版本:Ubuntu 20.04 有两块3090的显卡 下载相关文件首先下载源码,下载完成后解压得到QAnything-master文件夹 github下载地址:https://github.com/netease-youdao/qanything gitee下载地址:https://gitee.com/netease-youdao/QAnything?_from=gitee_search 下载emb…

03-支付服务

1. 交易流程 下面我们来看下基础服务组件中的交易模块,我们已完成结算功能,如图所示,在结算这个模块中我们都会进入到一个子流程【交易流程】:对于交易,大家应该都知道,就是买东西付款,卖东西收款,在任何一个盈利的系统中,都离不开交易模块,下图是一个扫码支付的粗略…

读天才与算法:人脑与AI的数学思维笔记03_AlphaGo

读天才与算法:人脑与AI的数学思维笔记03_AlphaGo1. 国际象棋 1.1. 1997年计算机“深蓝”(Deep Blue)击败了顶尖国际象棋手,但机器取代数学研究机构还言之尚早 1.2. 下国际象棋与数学的形式化证明颇有相似之处,但学者认为中国围棋的思维方式更能够体现数学家思考的创造性和…

框架图与动机结构化与可重定目标代码生成

框架图与动机结构化与可重定目标代码生成 用于数值计算的代码生成方法传统上侧重于优化循环嵌套的性能。相关分析侧重于标量元素,因为循环嵌套的主体通常计算单个元素。这样的分析必须考虑内存依赖性与混叠。这些方法在过去进行了深入研究,并已达到高度成熟。当从像C或Fortra…

MVCC

多版本并发控制,多个事物并发的情况下到底该访问哪个版本你解释一下MVCC?mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突, 它的底层实现主要是依赖了数据库中的三个部分,隐藏字段,undo log日志和readView读视图 隐藏字段是指:在mysql中给每…