高级数据结构与算法---莫队

news/2025/1/12 16:18:02/文章来源:https://www.cnblogs.com/fufufuf/p/18667025

这篇文章主要是用来复习的,最近学了一些新的东西,多少要记录一下,不然以后忘了,不过似乎树状数组和ST表还没有补完,等后面有时间(不能拖拉)再去将他们给写完,然后就开始去学习一下计算几何,树形DP以及图论,啊啊啊啊啊啊,还要准备数学建模,哎,为什么明明都放假了,还要给自己找这么多事情呢,躺着好好玩玩原神不香吗,不行,以后早上起床要多喊几声“我已经放假了”,“我已经放假了”,“我已经放假了”来告诉自己现在已经放假了,不然绷得太紧会绷不住的。

还有一件事,先立上flag,要好好找个时间做一下自己的网站,后面的博客会迁移到上面,除了这个之外,还要做一个AI的项目,以及读一读西瓜书,好像给自己的事情安排的太多了啊,算了,先开始讲东西吧,废话有一说一,自己都觉得太多了

首先是莫队,莫队是大神莫涛提出的全新的数据结构

这一位是真的神犇,前国家队队长,%%%,由于只学了普通的莫队,所以在这里将会去只讲普通的莫队算法(因为只学了这么多)

那么现在就是去看一下这个题目

这个题就是一个普通莫队的板子题(这个题也可以是用线段树,以及树状数组来解决,但是感觉莫队算是一个优雅的解法)所以就讲一下莫队``

首先,莫队是一种离线的做法,而不是一种在线的做法, 离线的含义即为他需要将所有的结果处理完之后,然后再来输出,而在线则是说去做出一个答案之后就马上输出,那么莫队又是什么呢,下面这句话非常关键。

如果在查询完区间[l , r] 之后,就去可以在O(1)的时间里面去查询[l+1,r], [l-1,r], [ l,r+1] ,[l, r-1] 区间里面的答案,那么他的速度就会快上很多倍。但是,这一看不就是双指针嘛,那又有什么用处呢,除了这个之外,还有分治,这样子处理起来效率就会快上不少了。

那么看一下怎么实现的,直接上AC的代码了,这样子比较好理解

首先,我们要写上一个结构体,去存储上每一个询问。这里我们会记录他的左区间和他的右区间,在这里,如下所示
struct mo { ll l, r, id,ans; };
然后id会记录他是第几个输入的数据,这个用处很大,后面会讲解到,然后ans是用来记录答案的。

在继续下一步之前,先来看一下莫队的时间复杂度证明,莫队算法会将整个序列分为√n块,首先对于左指针,需要移动√n次,而对于右指针,则是要移动n次,所以在这里,由于存在√n个快,所以在这里,总共的移动次数应该是不超过O(n√n+n)的,所以这个便是莫队算法的时间复杂度,为O(n√n)。

那么为什么要分为√n块呢,在这里,假设块长为s,那么现在就是有n/s个块,然后由于每个块存在m个询问,第i个块询问的数量为q,那么,最坏的时间复杂度应该是
 如下所示:

那么如果近似m和n,就可以知道最后的大小应该是√n,在这里就可以完成莫队算法的复杂度证明以及为什么要分成√n份。
n=read(); ll b = sqrt(n); for (int i = 1; i <= n; i++) { A[i]=read(); pe[i] = i / b; }
在这里作为输入端完成分块的操作。

那么在这里接下来就是莫队的精华,对于每一个询问的排序,若是两个询问的左边界在同一个块里面,那么这里就会去比较他们的右指针大小,否则就去比较他们的左指针的大小,如图是他们的比较代码。
inline bool cmp(mo a, mo b) { if (pe[a.l] == pe[b.l]) { return a.r < b.r; } return a.l < b.l; }
在这之后,就是关于指针的移动,主要是包括了remove 和 add 这两个算法,这里主要是去用来维护每个询问的ans,换言之,就是去求解。
`inline void add(ll i) {
//当前的数字不存在
if (!cnt[A[i]]) {
now++;
}
cnt[A[i]]++;
}

inline void rem(ll i) {
cnt[A[i]]--;
if (!cnt[A[i]]) {//当前的数字为0
now--;
}
} 会使用now变量来记录当前的答案。那么在这里,最后就是完整的代码了,#include<bits/stdc++.h>

define ll long long

const ll maxn = 1e6 + 7;
using namespace std;

struct mo {
ll l, r, id,ans;
};

inline ll read() {
ll x = 0;
ll 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;

}

ll pe[maxn];
ll A[maxn];//记录原始数组
ll cnt[maxn];//记录当前区间中每个数字的数量
mo mos[maxn];
ll n, m;
ll now = 0;

inline bool cmp(mo a, mo b) {
if (pe[a.l] == pe[b.l]) {
return a.r < b.r;
}
return a.l < b.l;
}

inline bool cmp2(mo a, mo b) {
return a.id < b.id;
}

inline void add(ll i) {
//当前的数字不存在
if (!cnt[A[i]]) {
now++;
}
cnt[A[i]]++;
}

inline void rem(ll i) {
cnt[A[i]]--;
if (!cnt[A[i]]) {//当前的数字为0
now--;
}
}

int main() {
n=read();
ll b = sqrt(n);
for (int i = 1; i <= n; i++) {
A[i]=read();
pe[i] = i / b;
}
m=read();
for (int i = 1; i <= m; i++) {
mos[i].l = read();
mos[i].r=read();
mos[i].id = i;
}

sort(mos + 1, mos + m + 1, cmp);
ll l = 1;
ll r = 0;
for (int i = 1; i <= m; i++) {while (l < mos[i].l) {rem(l++);}while (l > mos[i].l) {add(--l);}while (r < mos[i].r) {add(++r);}while (r > mos[i].r) {rem(r--);}mos[i].ans = now;
}
sort(mos + 1, mos + m + 1, cmp2);for (int i = 1; i <= m; i++) {cout<<mos[i].ans<<endl;
}

}
//树状数组可能是更优的解法,感觉,莫队会被卡掉
但是,这道题是用莫队会被卡掉,所以在这里,这道题过不了,但是可以看看数据弱化版的题目。 [](https://www.luogu.com.cn/problem/SP3267) [](https://www.spoj.com/problems/DQUERY/) 这个题可以过了,这里有两个链接,是同一个题目 [](https://www.luogu.com.cn/problem/P1494) 然后就就是这道题,也是一个莫队的题目,但是他会相对复杂一些,这里其实也是一个统计种类数的问题,那么同样,是用莫队去做这个题,首先还是对于每一个询问,重新排序,但是除了l 和r之外,在这里我们还要记录两个元素a,b用来最后求解答案,分别为当前袜子的总数,以及袜子的总种类数,那么,在这里,接下来就是去维护ans了,用来记录答案,对于每一个新加入的袜子,答案会增加他的同类袜子数量个,因为它可以与每一个同种类的袜子两两组合,所以说在这里就可以维护了,如下所示。inline void add(ll i) {
ans += mark[a[i]];
mark[a[i]]++;
}

inline void del(ll i) {
mark[a[i]]--;
ans -= mark[a[i]];
}`
对于分数化简,在这里,我们只要使用GCD即可。

最后代码如下所示。
`#include<bits/stdc++.h>

define ll long long

define maxn (ll)5e4+9

using namespace std;

struct mo {
ll l, r, id;
ll a, b;
}pe[maxn];

ll ans = 0;
ll mark[maxn];
ll pos[maxn], a[maxn];

inline void add(ll i) {
ans += mark[a[i]];
mark[a[i]]++;
}

inline void del(ll i) {
mark[a[i]]--;
ans -= mark[a[i]];
}

inline ll gcd(ll a, ll b) {
if (b != 0) {
return gcd(b, a % b);
}
return a;
}

inline bool cmp(mo a, mo b) {
return pos[a.l] == pos[b.l] ? a.r < b.r : a.l < b.l;
}

inline bool cmp2(mo a, mo b) {
return a.id < b.id;
}

int main() {
ll n, m;
cin >> n >> m;
ll b = sqrt(n);
ans = 0;
memset(mark, 0, sizeof(mark));

for (int i = 1; i <= n; i++) {cin >> a[i];pos[i] = i / b;
}for (int i = 1; i <= m; i++) {cin >> pe[i].l>> pe[i].r;pe[i].id = i;
}ll l = 1, r = 0;
sort(pe + 1, pe + m + 1, cmp);
for (int i = 1; i <= m; i++) {while (l < pe[i].l) {del(l++);}while (l > pe[i].l) {add(--l);}while (r > pe[i].r) {del(r--);}while (r < pe[i].r) {add(++r);}pe[i].a = ans;pe[i].b = (pe[i].r - pe[i].l + 1) * (pe[i].r - pe[i].l) / 2;if (ans == 0) {pe[i].b = 1;continue;}ll gcd1 = gcd(pe[i].a, pe[i].b);pe[i].a /= gcd1;pe[i].b /= gcd1;
}
sort(pe + 1, pe + m + 1, cmp2);
for (int i = 1; i <= m; i++) {cout << pe[i].a << '/' << pe[i].b << endl;
}
return 0;

}`
那么就到这里了

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

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

相关文章

AT_abc388_f Dangerous Sugoroku 题解

太幽默了。 显然可以用矩阵快速幂解决,矩阵里维护距离当前点 \(B\) 以内的所有点可不可达,转移只需分段,在区间内和不在区间内用不同的转移矩阵即可。复杂度 \(O(B^3m\log n)\)。 然后你就 T 了。 此时你很急,你现在应该快点卡常来 AK 这场比赛而不是研究其他的做法,于是我…

多路复用与多路分解

主机维护一个Socket表,通过表中记录的ipport与socket对应关系进行封装报文,接受到报文时使用报文的ip和port查找对应socket的过程 称为多路复用与多路分解 TCP socket存有本机进程到对端进程的映射关系UDPudp是无连接的,本机ip port没有和对端ip port构成映射关系,udp的soc…

计算机网络-多路复用与多路分解

主机维护一个Socket表,通过表中记录的ipport与socket对应关系进行封装报文,接受到报文时使用报文的ip和port查找对应socket的过程 称为多路复用与多路分解 TCP socket存有本机进程到对端进程的映射关系UDPudp是无连接的,本机ip port没有和对端ip port构成映射关系,udp的soc…

.NET 中管理 Web API 文档的两种方式

前言 在 .NET 开发中管理 Web API 文档是确保 API 易用性、可维护性和一致性的关键。今天大姚给大家分享两种在 .NET 中管理 Web API 文档的方式,希望可以帮助到有需要的同学。 Swashbuckle Swashbuckle.AspNetCore 是一个流行的 .NET 库,它使得在 ASP.NET Core 项目中自动生…

idea设置快捷键

idea设置快捷键 下载安装idea 参考:pyhton、miniConda、pycharm下载安装配置中的pycharm下载安装配置即可,jetbrains系列软件都可如此操作。 查询快捷键 打开安装好的idea, ctrl+alt+s或手动打开Settings/设置, 点击左侧Keymap/按键映射页签, 点击右侧搜索框右侧的放大镜,…

抖音评论生成器在线工具,好评生成器软件,用js+html即可实现

开发技术HTML:用于搭建页面结构。 CSS:用于美化页面样式。 JavaScript:实现核心逻辑,包括文案生成、随机选择、复制功能等。 部分框架代码:<!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name=…

Odoo18.0附件分享管理

需求背景 虽然odoo官方提供了文档的门户访问功能,外部用户可以在门户查看共享的文档和相关的附件。但是某些情况下,我们希望外部用户只能有限地能访问我们指定的附件,而不是能够访问整个文档和全部附件。 本文即是介绍为了解决此问题而开发的功能。 功能介绍 这里我们以销售…

git worktree同一个仓库多个分支并行开发和管理

Git Worktree 是 Git 提供的一个功能,允许你在同一个仓库中同时工作在多个工作目录中,每个目录都有自己的工作树和索引。这对于同时处理多个分支或版本非常有用。介绍 Git Worktree 是 Git 提供的一个功能,允许你在同一个仓库中同时工作在多个工作目录中,每个目录都有自己的…

idea汉化教程,jetbrains系列软件都适用

idea汉化教程,jetbrains系列软件都适用 下载安装idea 参考:pyhton、miniConda、pycharm下载安装配置中的pycharm下载安装配置即可,jetbrains系列软件都可如此操作。 汉化 打开安装好的idea, ctrl+alt+s或手动打开Settings/设置, 点击左侧Plugins/插件页签, 点击右侧Market…

搭建jumpserver堡垒机--基本使用(三)

一.给所有服务器设置只允许jumpserver机器登录(尽量不要操作)1.开放堡垒机ssh登录,xxx.xxx.xxx.xxx对应堡垒机ipiptables -A INPUT -s xxx.xxx.xxx.xxx -p tcp --dport 22 -j ACCEPT2.拒绝所有机器ssh登录iptables -A INPUT -p tcp --dport 22 -j REJECT 二. 配置邮箱和创建用…

【学习笔记】斜率优化 dp

LearningForeword 斜率优化,顾名思义就是用一次函数的单调性来优化 dp,具体表现为利用单调性找到最优决策点从而优化掉需要枚举的决策点。 给斜率优化 dp 总结一个模板: \[dp_{i} = \min\{dp_{j} + calc (i,j)\} \]或者: \[dp_{i} = \max\{dp_{j} + calc (i,j)\} \]其中 \(…

安装MM系统(使用systemback封装Ubuntu系统iso镜像)

哈喽啊亲们!今天又是阳光明媚的一天,不知道亲们想me了没,今天小橘给大家分享一下MM系统镜像的封装流程,欢迎大家一起探讨。一、安装 MM 系统到其他机器的硬盘上 (一) BMC 挂载镜像 设置--一般--媒体重定向设置--一般设置--远程媒体支持--挂载 CD/DVD--填写信息--保存--选择…