莫队(模板 + 带简单修改的莫队)

article/2025/8/8 21:43:04

莫队

这个算法的思想比较简单,我们在做RMQ类问题时,有多次询问的那种,其实在这些询问中有很多都是问的同一段区间,即有的区间被询问的多次,所以我们对询问进行一个排序,假设上次询问我们得到了区间[l,r]的值,那本次询问跟上次相比,多的我们加上即可,少的减掉即可。然后用到分块思想。

所以,比较重要的就是这个排序和每次询问与上次之间的转化
排序:这里用到分块,根据区间左界所在的块的序号从小到大排,若在同一区间,则根据序号的奇偶性,奇则根据右边界从小到大,偶则根据右边界从大到小
与上次的转化:通过四个while来实现

	while(l < ask[i].l) del(c[l++]);while(l > ask[i].l) add(c[--l]);while(r < ask[i].r) add(c[++r]);while(r > ask[i].r) del(c[r--]);

P1494 小z的袜子(模板题)

分析:
弄明白那个排列组合和概率就基本模板题惹

AC代码:

#include <bits/stdc++.h>using namespace std;
typedef long long ll;int n, m, len;
int ar[50050];
struct node
{ll l, r, id;
}ask[50050];
struct node1
{ll x, y;
}ans[50050], now;
int pos[50050];
ll cnt[50050];bool cmp(node a, node b)
{if(pos[a.l] == pos[b.l]){if(pos[a.l] & 1) return a.r < b.r;else return a.r > b.r;}else return pos[a.l] < pos[b.l];
}ll gcd(ll x, ll y)
{return !y ? x : gcd(y, x % y);
}void add(int x)
{++cnt[x];if(cnt[x] > 1)now.x = now.x + cnt[x] * (cnt[x] - 1) - (cnt[x] - 1) * (cnt[x] - 2);
}void del(int x)
{--cnt[x];if(cnt[x] > 0)now.x = now.x + cnt[x] * (cnt[x] - 1) - (cnt[x] + 1) * cnt[x];
}void divgcd(ll x, ll y, int id)
{if(!x) x = 0, y = 1;else{ll g = gcd(x, y);x /= g;y /= g;}ans[id].x = x;ans[id].y = y;
}int main()
{scanf("%d%d", &n, &m);len = sqrt(n + 0.5);for(int i = 1; i <= n; ++i){scanf("%d", &ar[i]);pos[i] = (i - 1) / len + 1;}for(int i = 1; i <= m; ++i){scanf("%lld%lld", &ask[i].l, &ask[i].r);ask[i].id = i;}sort(ask + 1, ask + m + 1, cmp);for(int i = ask[1].l; i <= ask[1].r; ++i) add(ar[i]);now.y = (ask[1].r - ask[1].l + 1) * (ask[1].r - ask[1].l);divgcd(now.x, now.y, ask[1].id);int l = ask[1].l, r = ask[1].r;for(int i = 2; i <= m; ++i){while(l < ask[i].l) del(ar[l++]);while(l > ask[i].l) add(ar[--l]);while(r > ask[i].r) del(ar[r--]);while(r < ask[i].r) add(ar[++r]);now.y = (ask[i].r - ask[i].l + 1) * (ask[i].r - ask[i].l);divgcd(now.x, now.y, ask[i].id);}for(int i = 1; i <= m; ++i) printf("%lld/%lld\n", ans[i].x, ans[i].y);return 0;
}

P1903 数颜色(带简单修改的莫队)

在这里插入图片描述

分析:
首先考虑普通的莫队,这个题带了修改,那么我们依旧按照莫队来做,我们需要记录一下当前这次询问经过了几次修改,然后跟上一次比较,那就跟普通莫队一样了,只是4个while要变成6个while了。这是大体方向,然后还有一点点细节
1.分块大小:sz = pow(n, 0.666);
2.排序:第一关键字是区间左界所在的块的序号,第二关键字是区间右界所在的块的序号,第三关键字是这次询问经过了几次修改,均按照从小到大排
3.对于修改,如果碰到某次修改需要操作,那么一定需要做一个交换swap(ar[qr[t].l], qr[t].r);,交换完之后,ar数组得到了修改,然后这次修改指令也得到了修改,因为后面再操作这次修改的时候就是改回来了,所以一个交换解决。另外,需要判断这次修改是不是发生在查询的区间内,是则需要做一些add和del
4.维护的容器,以及作用
cnt[i] : 数字i在当前区间出现的次数
ar[i]; 原数组在位置i应该是的值
qq[i] 表示第i次询问的左右边界已经发生在几次修改之后,id代表修改序号
qr[i] 表示第i次修改是将l位置的数字改成r

AC代码:

#include <bits/stdc++.h>using namespace std;int sum;
int cnt[1000050];
int ar[10050];
int ans[10050];
int cntq, cntr;
int n, m, sz;
char op[5];
int l, r;struct node
{int l, r, t, id;
}qq[10050], qr[10050];//两个数组分解记录每一个询问以及修改的状态inline bool cmp(const node &a, const node &b)
{if(a.l / sz == b.l / sz){if(a.r / sz == b.r / sz) return a.t < b.t;else return a.r < b.r;}else return a.l < b.l;
}inline void add(int x)
{sum += !cnt[x]++;
}inline void del(int x)
{sum -= !--cnt[x];
}inline void upd(int x, int t)//upd是对于时间上的变化所造成变化的维护
{if(qq[x].l <= qr[t].l && qr[t].l <= qq[x].r){del(ar[qr[t].l]);add(qr[t].r);}swap(ar[qr[t].l], qr[t].r);
}int main()
{scanf("%d%d", &n, &m);sz = pow(n, 0.666);for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);for(int i = 1; i <= m; ++i){scanf("%s%d%d", op, &l, &r);if(op[0] == 'Q'){++cntq;qq[cntq].id = cntq;qq[cntq].l = l;qq[cntq].r = r;qq[cntq].t = cntr;}else{++cntr;qr[cntr].l = l;qr[cntr].r = r;}}sort(qq + 1, qq + cntq + 1, cmp);int lcur = 1, rcur = 0, tcur = 0;for(int i = 1; i <= cntq; ++i){while(lcur > qq[i].l) add(ar[--lcur]);while(lcur < qq[i].l) del(ar[lcur++]);while(rcur > qq[i].r) del(ar[rcur--]);while(rcur < qq[i].r) add(ar[++rcur]);while(tcur < qq[i].t) upd(i, ++tcur);while(tcur > qq[i].t) upd(i, tcur--);//增加t轴上的移动ans[qq[i].id] = sum;}for(int i = 1; i <= cntq; ++i) printf("%d\n", ans[i]);return 0;
}

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

相关文章

莫队 - 基础与扩展

普通莫队 莫队可以说是一个算法&#xff0c;但更多是一种思想。 我们先来看看普通莫队解决的问题&#xff1a; 有一个长度为 n n n 的数列 a a a。 q q q 个询问&#xff1a; a a a 在 [ l i , r i ] [{l_i},r_i] [li​,ri​] 中有多少个不同的数。 不强制在线。 1 ≤ n …

莫队详解

莫队实际很简&#xff08;du&#xff09;单&#xff08;liu&#xff09; 依照某位dalao的说法&#xff0c;就是两只小手&#xff08;two-pointers&#xff09;瞎跳 一.莫队&#xff08;静态莫队&#xff09; 我们以Luogu P3901 数列找不同为例讲一下静态莫队 这道题是个绿题&am…

关于莫队

待补&#xff1a;树上莫队&#xff0c;二次离线莫队 关于莫队 其实是个神奇的暴力算法.. 通常就是一种处理区间的东西 通过上一次的的左端点和右端点跳来跳去 从而得到这次区间的值 很暴力啊...完全不用思考就能懂的 那么 接下来首先是 普通莫队 排序和移动两点提及一下 …

莫队(普通莫队,带修莫队,树上莫队)

听说 莫队算法是一种“优雅的暴力”&#xff08;小声bb&#xff09;。 普通莫队 1/ 引入 problem&#xff1a;给你一个长度为n的数组&#xff0c;有m次查询&#xff0c;每次查询询问一个区间[L, R]内有多少个不同的数。 首先想想暴力怎么做。 开一个数组用来记数&#xff0c…

回滚莫队解析

&#xff08;南昌理工ACM集训队&#xff09; 泻药&#xff0c;不匿&#xff08;bushi&#xff09; 浅谈莫队回滚莫队样例小结 浅谈莫队 莫队是要摸清回滚莫队必须掌握的前置技能(๑ŐдŐ)b 前两天打多校有幸接触了莫队算法&#xff0c;花了几天时间搞懂了这些东西&#xff0…

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

文章目录 问题引入介绍莫队算法及其实现过程时间复杂度莫队算法适用范围莫队奇偶优化普通莫队&#xff1a;小B的询问树上莫队&#xff1a;SP10707 COT2 - Count on a tree II回滚莫队&#xff1a;[PA2011]Kangaroos upd&#xff1a;2021-08-11&#xff1a;重新对博客进行了外观…

超全的莫队算法一遍过

前置知识&#xff1a;双指针、分块 简单概括而言&#xff0c;莫队是一个离线算法&#xff0c;核心思想是将所有的询问按照分块进行排序后&#xff0c;对于每个询问可以通过双指针增删数据来达到总体的复杂度。 莫队通常用来解决求一段区间内不同数的个数相关的问题。 目录 1、…

莫队(普通操作)C++

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

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

整理的算法模板合集&#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;在学习新的语言或编写简单测试代码时非常实用。 我常常用它来管理一些代码片段和测试不…