离线区间的神奇——莫队算法

  • 前言
  • 一、什么是莫队算法?
  • 二、例题分析:
    • 1.相关例题
    • 题目描述
    • 输入格式
    • 输出格式
      • 简单分析:
  • 三、莫队算法思想:
      • 那么要怎么做(预处理):莫队算法优化的核心是**分块和排序**
        • 举个例子:求给定区间内不重复数的个数
    • 时间复杂度简单分析
  • 莫队算法JAVA代码实现
    • 四、总结

前言

莫队算法是由莫涛提出的算法。在莫涛提出莫队算法之前,莫队算法已经在 Codeforces 的高手圈里小范围流传,但是莫涛是第一个对莫队算法进行详细归纳总结的人。


一、什么是莫队算法?

莫队算法是一种基于分块思想优化暴力算法,莫队算法主要的应用是用于离线解决通常不带修改只有查询的一类区间问题。莫队算法分为普通莫队树上莫队带修莫队,今天主要分享普通莫队算法。
同时莫队算法处理的查询问题必须是离线问题,如果是强制在线则不能使用莫队算法。
什么是强制在线?即,上次查询作为下一次查询的条件或者内容,此时不能使用莫队算法。

二、例题分析:

1.相关例题

题目描述

HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式

一行一个正整数 n,表示项链长度。
第二行 n 个正整数 ai1-ai,表示项链中第 ii 个贝壳的种类。

第三行一个整数 m,表示 HH 询问的个数。
接下来 m 行,每行两个整数 l-r,表示询问的区间。

输出格式

输出 m 行,每行一个整数,依次表示询问对应的答案。

输入输出样例

简单分析:

该题大概意思是在一段给定一段序列,同时m个询问:特定区间内有多少不重复数的个数。这题最简单做法无非暴力——用一个cnt 数组记录每个数值出现的次数,再暴力枚举l到r统计次数,最后再扫描一边cnt数组,统计不为0的个数,输出答案即可。设数组数值最大值为s,那么暴力解法的时间复杂度为 O(m(n+s))~O(n2) ,1e12的数据量大概率会超时。莫队算法在该类问题上能够有效地优化时间复杂度至 O(n*sqrt(n)) !

三、莫队算法思想:

两个询问的l和r之间的跳转可能会产生很大的开销,如果我们能够有效的利用上一次的询问结果,来对当前的询问查找进行优化那对我们的整体的计算量能够有效的缩减。一般来说,如果可以在 O(1) 内从 [L , R] 的答案转移到 [L+1/-1 , R+1/-1] 这四个与之紧邻的区间的答案,则可以考虑使用莫队,这也是莫队算法的出发点

那么要怎么做(预处理):莫队算法优化的核心是分块和排序

1.首先对整个序列进行分块,分块数为sprt(n)块;我们将大小为n的序列分为根号n个块,从1到根号n编号
2.对m个查询操作进行排序sort() ,以查询操作L所在的块 bel[L] 为第一关键词,R所在的块 bel[R] 为第二关键词对m个查询操作进行升序排序;排完序后我们再进行左右指针跳来跳去的操作,来实现查询操作**(相关细节优化奇偶化排序,进一步减少双指针的跳转)**。
莫队的精髓就在于,离线得到了一堆需要处理的区间后,合理的安排这些区间计算的次序以得到一个较优的复杂度

举个例子:求给定区间内不重复数的个数

给输入序列长度为 n 9
序列:2 5 6 1 2 3 5 2 1 sqrt(9)==3 将序列分成 3块
给定查询区间:[1 , 4] [2 , 3] [4 , 7] [7 , 8]
对应所属分块bel[i] = [1 , 2]、[1 , 1]、[2 , 3]、[ 3 , 3]
那么对查询操作进行排序[2 , 3] [1 , 4] [4 , 7] [7 , 8]

时间复杂度简单分析

通过维护双指针(主要包括删除和增加的操作),对询问进行回答输出。
接下来我们对维护双指针的时间复杂度(约等于整体算法的时间复杂度)进行分析,对于询问的跳转(双指针在询问转换时的维护)通常有两种情况,一是不在块内、二是在块内
首先如果不在块内(上例中查询2->3):对于L我们每次跳转距离最多是 sqrt(n) (分块数) , 对于R来说每次跳转最多距离为 n ,所以时间复杂度是nsqrt(n)。
二在块内的块内:同理分析可得时间复杂度为 n
sqrt(n) ;
所以我们发现所有操作(查询操作快排+维护)在极限情况下的时间复杂度是O(nlogn)+2O(nsqrt(n)) 所以整体的算法时间复杂度也是O(n*sqrt(n)) ;

莫队算法JAVA代码实现

根据开头例子洛谷 P1972题,给出JAVA代码

import java.util.*;
public class Main{final static int maxn = 1010000;static int[] aa=new int[maxn], cnt=new int[maxn], belong=new int[maxn];static int n, m, size, bnum;static long curAns;static long[] ans;static query[] queries;public static class query{int l, r, id;}public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();   // 序列长度size = (int) Math.sqrt(n);bnum = (int)Math.ceil((double)n/size);  // block size 块数for(int i = 1; i <= n; i++) aa[i] = in.nextInt();   // 整个序列读入m = in.nextInt();  // 询问次数ans = new long[m+1];queries = new query[m+1];for(int i = 1; i <= m; i++){queries[i] = new query();queries[i].l = in.nextInt();queries[i].r = in.nextInt();queries[i].id = i;//System.out.println(queries[i].l + "-" + queries[i].r + "-" + queries[i].id);}for(int i = 1; i <= bnum; ++i)      // 预处理序列索引分属的块for(int j = (i - 1) * size + 1; j <= i * size; ++j) {belong[j] = i;}// 对查询操作进行快速排序// 但在此之上,我们还可以进行常数优化:奇偶化排序。意为:如果belong[l] 是奇数,则将r顺序排序,否则将r逆序排序。Arrays.sort(queries,1,m+1,((a, b) ->(belong[a.l] ^ belong[b.l])!=0 ? belong[a.l] - belong[b.l] : ((belong[a.l] & 1)!=0 ? a.r - b.r : b.r - a.r)));//for(int i = 1; i <= m; i++)System.out.println(queries[i].l + "-" + queries[i].r + "-" + queries[i].id);int l = 1, r = 0;for(int i= 1; i <= m; i++){int qr = queries[i].r, ql = queries[i].l;
//            while(l < ql) del(l++); // 如左指针在查询区间左方,左指针向右移直到与查询区间左端点重合
//            while(l > ql) add(--l); // 如左指针在查询区间左端点右方,左指针左移
//            while(r < qr) add(++r); // 右指针在查询区间右端点左方,右指针右移
//            while(r > qr) del(r--); // 否则左移while(l < ql) curAns -= --cnt[aa[l++]]!=0 ? 0 : 1;while(l > ql) curAns += cnt[aa[--l]]++==0 ? 1 : 0;while(r < qr) curAns += cnt[aa[++r]]++==0 ? 1 : 0;while(r > qr) curAns -= --cnt[aa[r--]]!=0 ? 0 : 1;ans[queries[i].id] = curAns;}for(int i = 1; i <= m; i++)System.out.println(ans[i]);}
}

四、总结


使用该方法能通过上例大部分数据集(听说最近数据集加强了,所以java只能通过一半,不过这也可以当作一道莫队算法模板练习题)

这就是我个人对该算法的思路分享啦~
以上是个人的拙见,欢迎大家一起交流学习~

个人推文链接
个人博客网站

离线区间的神奇——莫队算法相关推荐

  1. [HDU](6333)Problem B. Harvest of Apples ---- 数论+莫队算法

    Problem Description There are n apples on a tree, numbered from 1 to n. Count the number of ways to ...

  2. NBUT 1457 Sona(莫队算法+离散化)

    [1457] Sona 时间限制: 5000 ms 内存限制: 65535 K 问题描述 Sona, Maven of the Strings. Of cause, she can play the ...

  3. 莫队算法讲解 (详尽版)

    莫队算法我早有耳闻..可惜前不久才去学习. 但是自己看了看论文,也就1h左右,就能够全部理解了. 也就是说其实这个算法不难.. 好了,让我们进入正题. 我们首先来看一道例题: Description ...

  4. XOR and Favorite Number CF340E 莫队算法

    题目链接 题意:求给定询问区间[L,R]问有多少连续区间异或值等k,多次询问可以离线. a[i]^a[i+1]^a[i+2]^a[n]=(a[1]^a[2]^a[3]^...^a[i-1])^(a[1 ...

  5. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 9894  Solved: 4561 [Su ...

  6. C++ 莫队算法(转)

    胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队 在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中,我使 ...

  7. hdu 5213(容斥原理+莫队算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5213 莫队算法是离线处理一类区间不修改查询类问题的算法.就是如果你知道了[L,R]的答案.你可以在O( ...

  8. BZOJ 2038: [2009国家集训队]小Z的袜子(莫队算法例题)

    Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只 ...

  9. 莫队算法(Mo's_Algorithm)

    一.定义 二.应用 莫队算法可用于解决一类可离线且在得到区间[l,r]的答案后,能在O(1)或O(log2⁡n)得到区间[l,r+1]或[l−1,r]的答案的问题 三.分析 http://www.cn ...

最新文章

  1. 牛客华为机试第2题python
  2. 5.13T1Send 题(send)
  3. windows API函数copyfile
  4. LINUX下简单制作QCOW2镜像
  5. 密码学专题 信息摘要和数字签名指令
  6. CIO常犯的五个错误
  7. asp+ajax菜单,AJAX_基于asp+ajax和数据库驱动的二级联动菜单,index.asp 页面代码 复制代码 代 - phpStudy...
  8. Sersync实时备份服务部署实践
  9. 【java笔记】泛型定义和使用
  10. ajax瀑布流 dede,dedecms加载更多,无限下拉瀑布流插件
  11. Spring Boot源码分析
  12. iconfont-矢量图标字体的运用
  13. 三维人体姿态估计年度进展综述(周晓巍教授)
  14. matlab中怎么设置母线,Matlab绘图教程
  15. 基于Hadoop的项目实战-职位数据综合分析
  16. 4.前端注册表单验证 表单回填
  17. QT5.14.1实现界面开场动画
  18. 相对路径与绝对路径的写法
  19. STM32之RGB灯仿真
  20. 【万字拆解】ChatGPT各项能力的起源

热门文章

  1. nacos配置不自动刷新
  2. 坚持#第38天~独在异乡为异客,每逢佳节倍思亲
  3. 苹果AppStore已经莫名撤下超一百万个中国应用了
  4. 云场景实践研究第86期:美甲帮
  5. 华为武长区笔试2017
  6. Real-Time Rendering——7.1 Planar Shadows平面阴影7.1.1 Projection Shadows投影阴影
  7. python星空画法教程_插画分享|零基础也能画好的星空和夕阳教程继续系列
  8. -Xms -Xmx -XX:PermSize -XX:MaxPermSize 的理解和区别
  9. binwalk 的安装和使用
  10. js中 map 遍历数组