首页 > 编程语言 >莫队算法(基础莫队)小结(也做markdown测试)

莫队算法(基础莫队)小结(也做markdown测试)

时间:2024-05-09 19:35:02浏览次数:28  
标签:markdown int 莫队 sqrt 端点 res 小结 指针

莫队

基础莫队

本质是通过排序优化了普通尺取法的时间复杂度。

考虑如果某一列询问的右端点是递增的,那么我们更新答案的时候,右指针只会从左往右移动,那么i指针的移动次数是$O(n)$的。

当然,我们不可能让左右端点都单调来做到总体$O(n)$。

考虑对左端点进行分块。

莫队排序:
左端点按照分块的编号来排,如果分块编号不同的话编号较小的靠前,如果相同的话右端点小的在前。可以证明这样排完序的话时间复杂度可以做到$O(n \sqrt n)$。

这样我们把区间分成了$\sqrt n$块,每块的长度都是$\sqrt n$,在每一块内部,所有查询的右端点是递增的。

右指针:在每一块内部,右端点递增,所以右端点走的总数不会超过$n$(注意每一块内部放的是左端点,右端点是完全有可能超出这个块的范围的,因此这里为$n$),一共有$\sqrt n$块,所以右端点总共走的次数不会超过$n \sqrt n$。

左指针:先考虑每一次询问:

  1. 左指针在块内部移动,块的长度是$\sqrt n$,因此最多只会移动$\sqrt n$次。

  2. 左指针在相邻两块之间移动,最坏是从第一个块的左端点移动到第二个块的右端点,因此最坏移动$2 \sqrt n$次。

因为有q次询问,所以1是$q \sqrt n$,2是$2n$。
因为一共有$\sqrt n$个块,我们从前往后要跨过$\sqrt n - 1$次,每次最多是$2 \sqrt n$,所以时间复杂度是$2n$。

所以总时间复杂度为$O(q \sqrt n)$。

// 代码为统计一段区间上是否有不相同的数,没有输出yes
int n, q;
int a[N];
vector<array<int, 3>> v;
int cnt[210];
int ans[N];
int len;

int get(int x) {
    return x / len;
}

void adds(int x, int &res) {
    if (!cnt[x]) res ++;
    cnt[x] ++;
}

void del(int x, int &res) {
    cnt[x] --;
    if (!cnt[x]) res --;
}

void solve() {
    cin >> n >> q;
    len = max(1, (int)sqrt((double)n * n / q));
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        a[i] += 100;
    }
    for (int i = 1; i <= q; i ++) {
        int l, r;
        cin >> l >> r;
        v.push_back({i, l, r});
    }
    auto cmp = [&](array<int, 3> &a, array<int, 3> &b) {
        int i = get(a[1]), j = get(b[1]);
        if (i != j) return i < j;
        return a[2] < b[2];
    };
    sort(v.begin(), v.end(), cmp);
    // i是右指针,j是左指针
    for (int k = 0, i = 0, j = 1, res = 0; k < q; k ++) {
        int id = v[k][0], l = v[k][1], r = v[k][2];
        while (i < r) adds(a[++ i], res);
        while (i > r) del(a[i --], res);
        while (j < l) del(a[j ++], res);
        while (j > l) adds(a[-- j], res);
        ans[id] = res;
    }
    for (int i = 1; i <= q; i ++)
        if (ans[i] == 1) cout << "YES\n";
        else cout << "NO\n";
}

标签:markdown,int,莫队,sqrt,端点,res,小结,指针
From: https://www.cnblogs.com/lightmon5210/p/18182952

相关文章

  • Markdown文件上传到博客图片处理
    Markdown文件上传到博客图片处理在本地编写Markdown文章并准备上传到博客园时,经常会遇到的一个挑战是本地图片无法直接显示,因为它们存储在本地文件系统中。为了解决这个问题,有两种常见的策略:1.第一种策略是将图片上传到图床,并在文章中直接使用图片的外部链接。这种方法的好处是......
  • markdownTest
    欢迎来到我的博客这是一篇简短的文章这里是一些介绍性的文本。Markdown非常适合写作,因为它的语法既简单又强大。主要特点易于学习:Markdown的语法非常直观。灵活性:适用于各种文档和在线发布。广泛支持:许多平台和编辑器都支持Markdown。代码示例defhello_world():pr......
  • Markdown学习
    Markdown学习二级标题三级标题字体两个*号粗体你好!一个*号斜体你好!三个*号斜+粗体你好!两个~好删除线你好!引用一个>+''学习java分割线三个-、*图片一个!![图片]()超链接[点击跳转到狂神说博客](狂神Java基础总结-凌易说-lingyisay-博客......
  • 使用pycnblog一键拖拽同步markdown和图片
    目录原因解决办法参考链接准备工作配置config.yaml其他设置图片运行原因本地使用Typora写完文档,上传博客园时,图片不能同步解决办法参考链接博客园上传markdown文件准备工作下载工具pycnblog安装Python3pipinstallpyyaml配置config.yamlblog_url:htt......
  • Markdown和Latex中文字上下标的方法
    技术背景在Markdown和Latex中,如果只是写公式,不论是行内公式还是行间公式,都可以直接使用^和_这两个符号实现上下标。但有个问题是,如果只是使用公式来做上下标,出来的字体是斜着的。例如这样的语法:$$P_{OK}$$输出结果是这样的:\[P_{OK}\]但是有些时候想要的字符不能使用斜体,这......
  • 字符串Str函数小结
    数据结构字符串Str函数总结·我们学习过很多关于求解字符串相关问题的函数,但是都是每遇到一次算认识了,一定程度上很少进行总结,最近又重新接触到了这类“Str函数”,发现自己还是有点掌握不牢固,以下仅是个人学习总结,有错误之处可指出。如上图所示,在man手册中有许多关于str的函数,......
  • CF940F.Machine Learning-带修莫队、Mex
    给一个序列\(a\),两个操作:1、给\(l,r\),设\(a_l,\dots,a_r\)这些数集中每个数\(v\)的出现次数是\(c_v\),要求\(\mathrm{mex}(c_i)\).2、单点修改\(1\leqn,q\leq10^5\),时限4s这种一眼看过去很难维护的信息,一般就先找找性质。首先注意到关键性质:要求的是出现次数......
  • Markdown学习
    markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习markdown学习Markdown语法形式文本替换链接图片链接分割线语法这个比较简单,如果要创建分隔线,在单独......
  • zotero添加markdown插件(Mac版)
    zotero安装官网下载地址:https://www.zotero.orgmarkdown插件下载下载地址:https://gitcode.com/fei0810/markdownhere4zotero/tree/master选择相应的.xpi文件插件安装步骤打开zotero,选择工具->附加组件选择installadd-onfromfile选中刚才下载的.xpi文件点......
  • 01、Markdown 语法
    标题#一级标题##二级标题###三级标题。。。(最多六级标题) 字体**hello**:粗体*hello*:斜体三个*:粗体+斜体~~hello~~:删除线 引用>引用文字 分割线---*** 图片![图片名字](图片路径) 超链接[超链接名字](URL) 列表1.A2.B3.C -A-B-C ......