首页 > 编程语言 >莫队算法C/C++实现

莫队算法C/C++实现

时间:2024-08-25 17:23:00浏览次数:9  
标签:int C++ 查询 算法 queries 区间 莫队

目录

简介

 算法原理

算法步骤

C++ 实现

应用场景


莫队算法(Mo's Algorithm)是一种用于解决区间查询和更新问题的算法,由俄罗斯选手莫洛佐夫(Mo Morozov)提出。它在算法竞赛和某些计算密集型任务中非常有用,尤其是在需要处理大量区间查询和更新操作时。莫队算法以其高效性和简洁性而闻名,特别适合处理离线问题,即所有查询都已知且不需要实时处理。

简介

在算法竞赛和某些计算密集型任务中,我们经常需要处理大量的区间查询和更新操作。传统的线段树或树状数组虽然能够处理这类问题,但在面对大量数据时,效率往往不尽如人意。莫队算法(Mo's Algorithm),由俄罗斯选手莫洛佐夫(Mo Morozov)提出,是一种高效的离线算法,特别适用于处理区间查询和更新问题。


 算法原理

莫队算法的核心思想是将所有的查询按照结束时间排序,然后使用一个双向指针扫描区间,这样可以保证在任何时刻,被处理的区间都是当前未结束的最小区间。算法的时间复杂度为 (O((n + q) \log n),其中 n 是区间的数量,q 是查询的数量。

算法步骤

1. 排序:将所有的查询按照结束时间进行排序。
2. 初始化:使用一个数组记录每个区间的活跃状态。
3. 扫描:使用两个指针,一个从左向右扫描,一个从右向左扫描,同时更新区间的活跃状态。
4. 处理查询:在扫描过程中,对于每个查询,根据当前的区间活跃状态计算结果。

C++ 实现

下面是一个简单的莫队算法的C++实现,用于计算区间和的查询。

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;

struct Query {
    int l, r, id;
};

int main() {
    int n, q;
    cin >> n >> q;
    vector<int> a(n + 1);
    vector<Query> queries(q);

    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }

    for (int i = 0; i < q; ++i) {
        cin >> queries[i].l >> queries[i].r;
        queries[i].id = i;
    }

    // 按照结束位置排序
    sort(queries.begin(), queries.end(), [](const Query &a, const Query &b) {
        return a.r < b.r;
    });

    vector<int> active(n + 1, 0);
    vector<long long> sums(q, 0);
    int j = 0;
    for (int i = 0, k = 0; i < q; ++i) {
        while (k < q && queries[k].r == i) {
            ++active[queries[k].l];
            k++;
        }
        while (j < q && queries[j].l <= i) {
            --active[queries[j].r + 1];
            j++;
        }

        long long sum = 0;
        for (int p = 1; p <= n; ++p) {
            if (active[p]) {
                sum += a[p];
            }
        }
        sums[queries[i].id] = sum;
    }

    for (int i = 0; i < q; ++i) {
        cout << sums[i] << endl;
    }

    return 0;
}

应用场景

莫队算法适用于需要处理大量区间查询和更新的场景,如计算几何、图论中的最短路径问题、网络流问题等。

希望这篇博客能够帮助大家理解并掌握莫队算法。如果你有任何问题或需要进一步的解释,请随时提问私信我。
 

标签:int,C++,查询,算法,queries,区间,莫队
From: https://blog.csdn.net/2401_86771711/article/details/141503833

相关文章

  • A*算法C/C++实现
    A*算法是一种在图形平面上,有多个节点的路径中,寻找一条从起始点(source)到目标点(goal)的最短遍历路径的算法。它属于启发式搜索算法,因为它使用启发式方法来计算图中的节点,从而减少实际计算的节点数量。A*(A星)算法是一种启发式搜索算法,用于在图中找到从起始点(source)到目标点(goal)的......
  • 信息学奥赛初赛天天练-75-NOIP2016普及组-完善程序-二分答案、二分查找、贪心算法、贪
    1完善程序(单选题,每小题3分,共30分)郊游活动有n名同学参加学校组织的郊游活动,已知学校给这n名同学的郊游总经费为A元,与此同时第i位同学自己携带了Mi元。为了方便郊游,活动地点提供B(≥n)辆自行车供人租用,租用第j辆自行车的价格为Cj元,每位同学可以使用自己携带的钱或......
  • 代码随想录DAY24 - 回溯算法 - 08/23
    目录分割回文串题干思路和代码递归法复原IP地址题干思路和代码子集(非重复)题干思路和代码方法一:修改子集大小方法二:收集树的每个节点子集Ⅱ(含重复)题干思路和代码方法一:先去重,记录每个元素重复的次数方法二:先排序,再树层去重使用unordered_set对树层去重......
  • 代码随想录DAY25 - 回溯算法 - 08/24
    目录非递减子序列题干思路和代码递归法递归优化全排列题干思路和代码递归法全排列Ⅱ题干思路和代码方法一:用集合set去重方法二:先排序,再用数组去重非递减子序列题干题目:给你一个整数数组nums,找出并返回所有该数组中不同的递增子序列,递增子序列中至少有......
  • 【C++PCL】点云处理贪婪三角化曲面重建
    作者:迅卓科技简介:本人从事过多项点云项目,并且负责的项目均已得到好评!公众号:迅卓科技,一个可以让您可以学习点云的好地方重点:每个模块都有参数如何调试的讲解,即调试某个参数对结果的影响是什么,大家有问题可以评论哈,如果文章有错误的地方,欢迎来指出错误的地方。目录   ......
  • 算法笔记|Day34动态规划VII
    算法笔记|Day34动态规划VII☆☆☆☆☆leetcode198.打家劫舍题目分析代码☆☆☆☆☆leetcode213.打家劫舍II题目分析代码☆☆☆☆☆leetcode337.打家劫舍III题目分析代码☆☆☆☆☆leetcode198.打家劫舍题目链接:leetcode198.打家劫舍题目分析1.dp数组含义:d......
  • [C++ Error] f0202.cpp(13): E2268 Call to undefined function 'system'
    system('pause');解决方法,修改代码:system("pause");[C++Error]f0202.cpp(13):E2268Calltoundefinedfunction'system'错误解释:这个错误表明您在C++代码中尝试调用了一个未定义的函数system。system函数是C标准库中的函数,用于执行一个字符串中给出的命令。在C++中,......
  • C++暂停黑窗口 system( “pause “);
    在编写的c++程序中,如果是窗口,有时会一闪就消失了,如果不想让其消失,在程序结尾处添加:system("pause");注意:不要再return的语句之后加,那样就执行不到了。分析:system()是调用系统命令;pause暂停命令;这样在运行到此处时,会显示“Pressanykeytocontinue...”也就是“按任意键......
  • C++拾趣——转换编译器生成的类型名为代码中的类型名
    大纲代码测试代码地址在软件开发中,特别是在使用C++这类静态类型语言时,编译器在编译过程中会生成许多内部表示,包括类型信息。这些内部类型名通常用于编译器的内部处理,比如类型检查、优化和代码生成等。然而,在编写源代码或进行调试时,我们更习惯于使用人类可读和易于理......
  • 【scikit-opt】七大启发式算法的使用
    @目录前言1.测试函数1.1针状函数1.1.1表达式1.1.2特征1.1.3图像1.2Brains’srcos函数1.2.1表达式1.2.2特征1.2.3图像1.3Griewank函数1.3.1表达式1.3.2特征1.3.3图像1.4Easom’s函数1.4.1表达式1.4.2特征1.4.3图像1.5Schwefel’s函数1.5.1表达式1.5.2特征1.5.3......