莫队(普通操作)C++

article/2025/8/8 21:44:36

由于&R闲着无聊,今天上午学习的莫队也并不是完全掌握,老师才发的PPT也没有保存,于是决定乱写一篇靠着自己的理解写一篇关于莫队用法的博客......如果有错的麻烦之处,纯属&R自己理解有问题哈。

一.莫队的含义

莫队是在一篇国家集训队的论文中被提出的。本文只讨论普通的莫队用法。

莫队其实就是一种比较优雅的暴力算法,它只能支持离线计算,时间复杂度为O(m+n)sqrt(n)

其中操作的具体方法是,将需要操作的数列,按一定规则排序,规定左端点和右端点,然后将每次计算数列值的时候将左端点和右端点移到目标点上,边移动遍计算。这样的好处是可以避免一些重复计算,这样说可能有亿点点抽象,我们还是先来看一下一些关于莫队的具体操作吧。如果看不懂,我们可以先看第三大点的例题,结合起来看。是复习的话当我没说

二.莫队的基本操作

由于写作水品不加,于是决定先甩一堆模板

1.添加点

void add(int i)
{if(cnt[a[i]] == 0)	cur ++ ;cnt[a[i]] ++ ;
}

2.删除点

void del(int i)
{cnt[a[i]] -- ;if(cnt[a[i]] == 0)	cur -- ;	
}

3.bool排序

(1)未优化

bool cmp(Node a, Node b)
{int Num = sqrt(n) ;return (a.l/Num != b.l/Num)?a.l<b.l:a.r<b.r ;
}

(2)奇偶优化

bool cmp(Node a, Node b)
{int Num = sqrt(n) ;return (a.l/Num != b.l/Num)?a.l<b.l:((a.l/Num)&1)?a.r<b.r:a.r>b.r ;
}

备注:!=可以改成^(这样更快),&的等于% 2 == 1。

4.移点的具体操作

void Moteam()
{for(int i = 1; i <= m; i ++){while(l < P[i].l) del(l ++) ;while(r < P[i].r) add(++ r) ;while(l > P[i].l) add(-- l) ;while(r > P[i].r) del(r --) ;ans[P[i].id] = cur ;}
}

备注:因为是离线操作,所以拍完序后顺序会被打乱,我没输出时必须还是要按原来的顺序输出,所以需要保存每个点原先进来的id

三.例题

茫然的我于是决定写几道例题来看看,感觉是自己写给自己理解的QAQ

1.HH的项链

(1)题目描述

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

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

(2)输入格式

第一行:一个整数N,表示项链的长度。

第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。

第三行:一个整数M,表示HH 询问的个数。

接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

(3)输出格式

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

(4)样例

样例输入

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

样例输出

2
2
4

(5)数据范围与提示

对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000;

(6)题目分析

没什么好分析的不就是板子题吗?

        我们想想(用莫队想哈,虽然树状数组也能做Q^Q),如果我们用正常的超级暴力的想法来做的话,我们就需要先枚举m,然后从左端点开始枚举,枚举到右端点,用一个数组来判断这个数是否是第一次出现,如果是的话,我们就将ans累加,最后输出,清零,进行m操作即可,时间复杂度为O(mn)。

        于是我们决定将这个暴力打的优雅一点点。

        我们先思考,假设我们计算了1到4的,然后我们又要计算2到5,那么2到4这个部分就会重复计算,还不如令l = 1, r = 4,用cnt[i]来存储i出现的次数,用cur来表示目前一共出现了多少个没有重复的数。那么l向右移动后,”原先那个数“的个数cnt[l(这里的l是还没移动的坐标)]就会减一,如果个数变成零,那么cur随之减少1。r向右移动,如果cnt[Num[r]]==0,那么就说明这个数是第一次出现,cur++。

        一共有四种情况,详细见二.1.2.4.

        那么这样真的能优化吗?如果左右两个点总是跨度很大,那么我们不如暴力

        智慧的前辈们已经替我们解决了这个问题。

        我们可以将这一条线分成很多组,经过平衡,分成根号(n)组是最合适的。所以我们尽量控制左端点在根号n的范围内移动,右端点在n的范围内移动,所以就有了二.3.(1)的排序

        可是我们还有一种更优的排序方法二.3.(2)

        我们思考当第一组(共根号n组)的r移动到最右边时(r是按从左到右排了序的),我们在计算第二组的时候为了让r少跑一点,于是将r从右到左排序,于是就有了奇数组按a.r < b.r, 偶数组按a.r > b.r的排序方法

        

#include <bits/stdc++.h>
using namespace std ;
const int MAXM = 200005 ;
int n, a[50005], m, cur = 0, cnt[1000005], Num = 1, l = 1, r = 0, ans[MAXM] ;
struct Node
{int l, r, id ;
}P[MAXM] ;
bool cmp(Node a, Node b){return (a.l / Num) != (b.l / Num) ? a.l < b.l : ((a.l / Num) & 1) ? a.r < b.r : a.r > b.r ;
}
int read()
{int x = 0, f = 1 ;char c = getchar() ;while(c < '0' || c > '9'){if(c == '-')	f = -1 ;c = getchar() ;}while(c >= '0' && c <= '9'){x = x * 10 + c - '0' ;c = getchar() ;}return x * f ;
}
void add(int i)
{if(cnt[a[i]] == 0)	cur ++ ;cnt[a[i]] ++ ; 
}
void det(int i)
{cnt[a[i]] -- ;if(cnt[a[i]] == 0)	cur -- ;
}
void Moteam()
{for(int i = 1; i <= m; i ++){while(l < P[i].l){det(l ++) ;}while(r < P[i].r){add(++ r) ;}while(l > P[i].l){add(-- l) ;}while(r > P[i].r){det(r --) ;}ans[P[i].id] = cur ;}
}
void Init()
{n = read() ;memset(cnt, 0, sizeof(cnt)) ;Num = (int)sqrt(n) ;for(int i = 1; i <= n; i ++){a[i] = read() ;}m = read() ;for(int i = 1; i <= m; i ++){P[i].l = read(), P[i].r = read(), P[i].id = i ;}sort(P + 1, P + m + 1, cmp) ;
}
int main()
{Init() ;Moteam() ;for(int i = 1; i <= m; i ++){printf("%d\n", ans[i]) ;}
}

        


http://chatgpt.dhexx.cn/article/vgRKiaTN.shtml

相关文章

【算法笔记】莫队算法(基础莫队,带修莫队,回滚莫队,树上莫队,二次离线莫队)

整理的算法模板合集&#xff1a; ACM模板 目录 1. 基础莫队2. 带修莫队3. 回滚莫队4. 树上莫队5. 二次离线莫队6. 在线莫队 来这里学习莫队以及神奇的证明&#xff1a;莫队算法 --算法竞赛专题解析&#xff08;26&#xff09; 我们首先考虑双指针的暴力法&#xff0c;发现很容…

linux(vscode)配置coderunner for python3

1.Python3 安装路径查看 which python3 2.vscode扩展中安装coderunner 3.配置coderunner 管理->设置->扩展->coderunner,找到下图所示内容&#xff0c;选择在settings.json中编辑。 在文件中输入code-runner.executorMap&#xff0c;会自动补全代码&#xff0c;如…

问题解决:VSCode Code Runner输出中文乱码

用vscode code runner插件经常会出现输出中文乱码的问题 那么如何解决这个问题呢&#xff1f; 解决方法&#xff1a; 通过设置&#xff0c;可以把代码放到 VS Code 内置的 Terminal 来运行&#xff0c;那么问题就能迎刃而解了。 选择 文件 -> 首选项 -> 设置&#xff0c…

VSCode——使用CodeRunner开发python输出中文出现乱码的解决方法

目录 方法一&#xff1a;每次都要加 方法二&#xff1a;一劳永逸 方法一 在程序中加入如下代码强行控制输出格式为utf-8即可 # -*- coding: utf-8 -*- import sys import io sys.stdoutio.TextIOWrapper(sys.stdout.buffer,encodingutf8)#改变默认输出的标准编码 编码改变…

修改CodeRunner快捷键

默认运行是 alt ctrl N, 改为alt ctrl r. run改更合理。 停止改为alt ctrl s stop也更合理&#x1f43b;

vscode用CodeRunner运行C++文件,提示系统找不到路径

问题描述 如图&#xff0c;直接点运行出现如下提示&#xff1a; 但是分开执行还是正常的&#xff1a; 原因 cmd执行多条语句要使用" && “作为连接符&#xff0c;对应的powerShell要用” ; "。 解决 在用户设置中修改code-runner.executorMap中对应的值…

vscode_Code Runner(codeRunner)配置(自定义输入映射内容)/指定.c/.cpp编译选型/编译运行含有中文名的文件示例(最佳实践)

文章目录 声明:文件(目录)中包含中文的问题关于配置调试功能(推荐) 找到配置入口点击在setting.json中编辑可以指定各种语言的命令行映射,这里以c语言指定以c99编译修改为例.可见到,届时编译.c文件的时候就会是以C99的标准指定编译. 运行效果 声明:文件(目录)中包含中文的问题 …

用VSCode 编写C++ 引入自定义头文件容易犯的错 和CodeRunner配置

问题描述 undefined reference to log(char const*) collect2.exe: error: ld returned 1 exit status 原因分析&#xff1a; 一般是由于c编译时&#xff0c;.cpp源文件未找到引起的 解决方案&#xff1a; 1.正确操作 一.例如你一个文件下有一个.h的文件和一个.cpp的文件 在v…

VSCode用Code Runner编译运行c/c++

首先vscode需要在文件夹下打开&#xff0c;以下所有的文件都需要放到你编写程序文件夹下的.vscode文件夹里 平时可以右击文件夹&#xff0c;选择open with code&#xff0c;结构应该是这样的 配置CodeRunner 下载 左下角齿轮找到设置 在扩展中找到Run Code configuration,点击…

【Mac】VScode配置Python开发环境详细教程(报错解决Import Error No module named ) CodeRunner插件

文章目录 在VScode中安装python插件解决报错SyntaxError: Non-ASCII character \xef in file解决报错"No module named xxx "VScode上使用Jupyter Notebook的方法20.02.26 最新方法&#xff1a;Code Runner插件一键安装&#xff08;python、java、C&#xff09;终端目…

CodeRunner插件:自定义编译参数

在设置里找到Coderunner选项&#xff0c;然后找到executorMap 点击 在 settings.json 中编辑 &#xff0c;你将看到对不同语言的编译指令。 以下为本人设置&#xff0c;为Mac系统&#xff0c;指令有所不同&#xff0c;不过操作流程是一样的。 "code-runner.executorMap…

java扩展包_CodeRunner 的 Java 扩展 Jar 包支持

CodeRunner 介绍 CodeRunner 是 Mac 上一款功能强大但使用简单代码工具&#xff0c;官方介绍支持几乎所有语言(20种语言)&#xff0c;同时支持语法高亮、代码提示和多种界面主题&#xff0c;在学习新的语言或编写简单测试代码时非常实用。 我常常用它来管理一些代码片段和测试不…

vscode 中 coderunner无法运行dart程序

如果你的vscode使用了CodeRunner&#xff0c;运行dart文件出错找不到dart的情况下: /bin/sh: dart: command not found可以直接修改coderunner扩展配置信息, 将其路径改为你希望的位置

vscode使用codeRunner将c/c++程序运行到外部控制台窗口

需要先关闭codeRunner的Run in Terminal 只需要在codeRunner的setting中&#xff0c;在从c/c的设置命令中添加 start cmd /c //或者/k /** 如果添加的是/c&#xff0c;则需要在程序的末尾添加system("pause"),不然会一闪而过&#xff0c; /k则不需要&#xff0c;不…

CodeRunner破解

CodeRunner2是Mac系统下的一款编程软件&#xff0c;支持23种语言和.txt文档制作&#xff0c;比Xcode都强大&#xff0c;Xcode只支持4种语言&#xff0c;原来的破解补丁有联网验证的问题&#xff0c;现在我做了程序防止联网验证。 破解方法&#xff1a;先下载CodeRunner2&#x…

windows系统VS code coderunner 运行shell脚本

无需设置环境变量&#xff0c;即可运行。 shell脚本第一行不要指定shell&#xff0c;什么“#!/bin/bash"不要写&#xff0c;这个会覆盖掉coderunner的设置。 在vs code设置中搜索“Code-runner: Executor Map” 点击“在setting.json中编辑” 修改shellscript后面引号里…

macOS使用CodeRunner快速配置fortran环境

个人网站:xzajyjs.cn 由于一些项目的缘故&#xff0c;需要有fortran的需求&#xff0c;但由于是M1 mac的缘故&#xff0c;不能像windows那样直接使用vsivf这种经典配置。搜了一下网上主流的跨平台方案&#xff0c;主要是gfortran&#xff0c;最近用Coderunner&#xff08;主要…

coderunner运行c语言提示错误,vscode安装及使用coderunner运行C程序教程

vscode简介 ​ vscode 全称 visual studio code&#xff0c;是一个运行于 OS X&#xff0c;Windows 和 Linux 之上的&#xff0c;针对于编写现代web和云应用的跨平台编辑器。除了上述提到的&#xff0c;它在c/c的编写上也有非常优秀的表现&#xff0c;并且有着十分友好的快捷键…

vscode_CodeRunner_tempCodeRunnerFile是个啥?

文章目录 是你选中的代码片段后,按下了codeRunner快捷键后创建的文件 是你选中的代码片段后,按下了codeRunner快捷键后创建的文件 这个运行选中代码片段的功能不是很常(实)用,不过知道怎么规避这种文件的创建就可以了(即,运行是不要选中编辑器中的代码片段)

windows 下vscode coderunner+bash 编程

起因是学弟按照教程配置gcc,g无果。编译还是出问题&#xff0c;coderunner的原理是在终端运行命令&#xff0c;我索性用wsl的bash替换原始的终端。 首先安装wsl。 如果点击打开出现 WslRegisterDistribution failed with error: 0x8007019e 管理员打开powershell 输入 Enab…