文章目录

  • 问题引入
  • 介绍莫队算法及其实现过程
  • 时间复杂度
  • 莫队算法适用范围
  • 莫队奇偶优化
  • 普通莫队:小B的询问
  • 树上莫队:SP10707 COT2 - Count on a tree II
  • 回滚莫队:[PA2011]Kangaroos

upd:2021-08-11:重新对博客进行了外观美化修正,以及新增树上莫队
upd:2021-08-19:新增回滚莫队

问题引入

给定一个大小为NNN的数组,数组中所有元素的大小≤N\le N≤N。你需要回答MMM个查询。
每个查询的形式是L,RL,RL,R。你需要回答在范围[L,R][L,R][L,R]中至少重复222次的数字的个数


如果按照以往的想法,就会是O(n2)O(n^2)O(n2)的暴力枚举

for ( int i = 1;i <= Q;i ++ ) {scanf ( "%d %d", &l, &r );for ( int j = l;j <= r;j ++ ) {count[a[j]] ++;if ( count[a[j]] == 3 )result ++;}}

就算加一些优化,用l,rl,rl,r采取指针转移,但总归上还是在[1,n][1,n][1,n]区间内进行移动

最坏多半也是逼近于O(n2)O(n^2)O(n2)​

void add ( int x ) {count[a[x]] ++;if ( count[a[x]] == 3 )result ++;
}
void removed ( int x ) {count[a[x]] --;if ( count[a[x]] == 2 )result --;
}
for ( int i = 1;i <= m;i ++ ) {scanf ( "%d %d", &l, &r );while ( curl < l )removed ( curl ++ );while ( curl > l )add ( -- curl );while ( curr > r )removed ( curr -- );while ( curr < r )add ( ++ curr );printf ( "%d\n", result );
}

add ​添加该位置的元素到当前集合内,并且更新答案

remove 从当前集合内删除该位置的元素,并更新答案


那么这个时候莫队算法就重磅登场了

为什么叫做莫队算法呢?

据说算法是由之前的国家队队长莫涛发明的,他的队友平日里称他为莫队,所以称之为莫队算法


介绍莫队算法及其实现过程

莫队算法就是一个离线算法,仅仅调整了处理查询的顺序

实现过程如下:

  • 将给定的输入数组分为n\sqrt{n}n​​​​​​块。每一块的大小为 nn\frac{n}{\sqrt{n}}n​n​​

    每个LLL​​​​落入其中的一块,每个RRR也落入其中的一块

    如果某查询的LLL​​​落在第iii​​块中,则该查询属于第iii​块​​

  • 所有的询问首先按照所在块的编号升序排列(所在块的编号是指询问的L属于的块

    如果编号相同,则按R值升序排列

  • 莫队算法将依次处理第111块中的查询,然后处理第222块.........直到最后一块

    有很多的查询属于同一块

e.g.

假设我们有333​​个大小为333​的块(0−2,3−5,6−8)(0-2,3-5,6-8)(0−2,3−5,6−8): {0,3}{1,7}{2,8}{7,8}{4,8}{4,4}{1,2}\{0,3\} \{1, 7\} \{2, 8\} \{7, 8\} \{4, 8\} \{4, 4\} \{1, 2\}{0,3}{1,7}{2,8}{7,8}{4,8}{4,4}{1,2}

先根据所在块的编号重新排列它们

  • 第111块:{0,3}{1,7}{2,8}{1,2}\{0, 3\} \{1, 7\} \{2, 8\} \{1, 2\}{0,3}{1,7}{2,8}{1,2}
  • 第222块:{4,8}{4,4}\{4, 8\} \{4, 4\}{4,8}{4,4}
  • 第333​块:{7,8}\{7, 8\}{7,8}

接下来按照R的值重新排列

  • 第一块:{1,2}{0,3}{1,7}{2,8}\{1, 2\} \{0, 3\} \{1, 7\} \{2, 8\}{1,2}{0,3}{1,7}{2,8}
  • 第二块:{4,4}{4,8}\{4, 4\} \{4, 8\}{4,4}{4,8}
  • 第三块: {7,8}\{7, 8\}{7,8}

上述过程只是重新排列了查询的顺序


时间复杂度

我们说了这么多,选用莫队算法无非就是想把时间复杂度给降下来

接下来我们来看看真正莫队的时间复杂度是多少,其实我看了很多博客也是有点懵逼

上面的代码就是起一个铺垫作用,所有查询的复杂性是由444个``while`循环决定的

前222​​个while循环可以理解为左指针curl的移动总量

后222​​个 while循环可以理解为右指针curr的移动总量

这两者的和将是总复杂性


先算右指针

对于每个块,查询是递增的顺序排序,所以右指针curr按照递增的顺序移动

在下一个块的开始时,指针可能在最右端,将移动到下一个块中的最小的RRR处

又可以从本块最左端移动到最右端

这意味着对于一个给定的块,右指针移动的量是O(n)O(n)O(n)(curr可以从111跑到最后的nnn)

我们有O(n)O(\sqrt{n})O(n​)​块,所以总共是O(nn)O(n\sqrt{n})O(nn​)​​


接下来看看左指针怎样移动

对于每个块,所有查询的左指针落在同一个块中,从一个查询移动到下一个查询左指针会移动

但由于前一个LLL​与下一个LLL在同一块中,此移动是O(n)O(\sqrt{n})O(n​)​​​(块的大小)

在每一块中左指针的移动总量是O(Qn)O(Q\sqrt{n})O(Qn​)​​,(QQQ是落在那个块的查询的数量)

对于所有的块,总的复杂度为O(m∗n)O(m∗\sqrt{n})O(m∗n​)​​


综上,总复杂度为O((n+m)∗n)=O(n∗n)O((n+m)∗\sqrt{n})=O(n∗\sqrt n)O((n+m)∗n​)=O(n∗n​)​

实在无法理解就跳过吧(如果有通俗易懂的解释欢迎评论)

莫队算法适用范围

首先莫队算法是一个离线算法,所以如果问题是在线操作带修或者强制特殊的顺序

莫队就失去了它的效应


其次一个重要的限制性:addremove的操作

当有些题目的addremove耗时很大,O(N)O(\sqrt N)O(N​)​​​​时就应该思考能否卡过

因为莫队本身就是一种优美的暴力而已

但是还是有很大一部分区间查询的题可以由莫队进行完成

莫队奇偶优化

sqt = sqrt( n )
bool cmp( node x, node y ) {return ( x.l / sqt == y.l / sqt ) ? ( ( ( x.l / sqt ) & 1 ) ? x.r < y.r : x.r > y.r ) : x.l < y.l;
}

普通莫队:小B的询问

小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,
每个询问给定一个区间[L…R],求Sigma(c(i)^2)的值,
其中i的值从1到K,其中c(i)表示数字i在[L…R]中的重复次数。
小B请你帮助他回答询问。

输入格式
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。

输入输出样例
输入
6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6
输出
6
9
5
2
说明/提示
对于全部的数据,1<=N、M、K<=50000

简单题解

说了是算法模板入门题,肯定不会把你拒之门外,还是要让你摸摸门的

这个题就是要简单处理一下∑ci2∑c_i^2∑ci2​​,当ci±1c_i±1ci​±1​时,答案会发生怎样的转化?

完全平方公式大家都会吧!!!

【莫队/树上莫队/回滚莫队】原理详解及例题:小B的询问(普通莫队),Count on a tree II(树上莫队),kangaroos(回滚莫队)相关推荐

  1. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  2. python判断是否回文_对python判断是否回文数的实例详解

    设n是一任意自然数.若将n的各位数字反向排列所得自然数n1与n相等,则称n为一回文数.例如,若n=1234321,则称n为一回文数:但若n=1234567,则n不是回文数. 上面的解释就是说回文数和逆 ...

  3. php渲染nodejs api,nodejs通过响应回写渲染页面步骤详解

    这次给大家带来nodejs通过响应回写渲染页面步骤详解,nodejs通过响应回写渲染页面的注意事项有哪些,下面就是实战案例,一起来看一下. 我们一般通过node框架提供的api操作页面渲染,如何利用原 ...

  4. JAVA算法:回文字符串相关问题详解(回文字符串总结)

    JAVA算法:回文字符串相关问题详解(回文字符串总结) Q1. 编写一个工具方法判断给定的字符串是否为回文字符串 例如:给定一个字符串"aabbaa",判断该字符串是否为回文字符串 ...

  5. C/C++实现回文质数(超详解)【沈七】

    C/C++实现回文质数(超详解) 题目链接 题目描述 输入样例 **题解部分** **完整代码** **未完待续** 参考文章 唤我沈七就行嘿嘿. 大一软件工程在读. 菜鸡蒟蒻想在博客中记录一些算法学 ...

  6. c++数据结构中 顺序队列的队首队尾_数据结构与算法—队列图文详解

    前言 栈和队列是一对好兄弟,前面我们介绍过数据结构与算法-栈详解,那么栈的机制相对简单,后入先出,就像进入一个狭小的山洞,山洞只有一个出口,只能后进先出(在外面的先出去).而队列就好比是一个隧道,后面 ...

  7. RocketMQ事务消息从生产到消费原理详解(包括回查过程)

    名词解释 half消息(生产者发送的Prepare消息):发送到MQ Server但无法被consumer消费的消息,暂时存在MQ Server,需要收到生产者二次确认后才能被消费 消息回查:一些意外 ...

  8. 【SPOJ COT2】Count on a tree II,树上莫队

    Time:2016.09.07 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 第一次写树上莫队 被char哥怒裱一通 实际上还是比较简单的 序列的相关维护问题转移到树上一般都要涉及 ...

  9. SP10707 COT2 - Count on a tree II【树上莫队】

    传送门 给定一颗无根树,求树上两点路径上的节点有多少不同的数字 可以离线 分析 前提,能够通过某种操作,将树上路径问题,转化成区间问题 这样,类似于求区间不同数,区间众数,区间mex等操作就能通过莫队 ...

最新文章

  1. Linux中的目录和文件管理
  2. Python一亿以内的素数个数_Python 计数质数
  3. 【Java程序设计】运算符与优先级
  4. 剑指_6从尾到头打印链表(Python)
  5. Java语言中的----继承(二)
  6. 企业微信如何做社群运营?企业微信群运营新玩法(可复用)
  7. 华为确定发布鸿蒙的时间了吗,Mate40系列首发,华为鸿蒙OS手机版发布时间确定...
  8. 计算机操作透明化,win10系统如何设置透明化效|win10电脑透明化功能怎么开启
  9. Math对象属性与方法
  10. .Net MAUI 安卓状态栏透明、半透明、全屏
  11. 马蜂窝裁php换java,php又又又凉凉了吗
  12. ffmpeg mplayer x264 代码重点详解 详细分析
  13. linux增加预读缓存区大小,Linux blockdev命令设置文件预读大小介绍
  14. 大学一路走来总结(技术)
  15. Neo4j Desktop版本的安装学习
  16. 005__Hadoop常用命令大全
  17. Unity3D命令手册
  18. 微信公开课,视频号成主角,机会来了
  19. Unity实战篇 | 自己制作一个《大转盘抽奖》 小程序,顺便带你看看抽奖的水可以有多深
  20. 自监督学习和计算机视觉

热门文章

  1. 当你老了,一生最后悔什么?大数据告诉你!
  2. ant vue 语言_Ant Design Vue是什么
  3. python pp模块_Python模块--Pexpect
  4. python多线程队列处理_Python线程和队列使用的一点思考
  5. 线程打印_面试题:用程序实现两个线程交替打印 0~100 的奇偶数
  6. get+php+mysql_Apache+PHP+MySql 的安装及配置
  7. 多个cpp文件生成so_boostpython:从多个.cpp文件创建一个模块(.so)
  8. linux c 数据库访问框架,linux c 开发通用结构,框架
  9. 每天都在红绿灯前面梭行,不如自己来实现个红绿灯?
  10. matlab程序改为m文件名,在MATLAB中,程序文件的扩展名为.m,所以程序文件也称为M文件...