莫隊(基礎版)優雅的暴力

?莫隊算法是一種離線算法,常用于高效處理區間查詢問題。它通過合理排序和移動左右端點來減少時間復雜度。

基本思想

莫隊算法的核心思想是將所有查詢離線排序!!(找出一個過起來最快的查詢順序),然后通過移動當前區間的左右端點來處理每個查詢。排序的方式通常是按照分塊(也稱為 "塊")進行,這樣可以將時間復雜度優化到 O (n√n)。

比如,查詢(1,99)(2,7)(1,97)(3,20)

如果直接暴力,,呵呵,如果直接利用左右端點移動更新,會反復橫跳,但是如果改變查詢順序,

(2,7)(3,20)(1,97)(1,99)就不怎么跳了

ps:端點移動:就是比如你先暴力了2-7的數,并且記錄了各個數有幾次(cnt),并且保留2-7的種類數,那么接下來查詢3-20,你就可以移動左端,變成3,此時把原本2的數給減了(cnt[?]--),如果這個減了后變成0,說明這個查詢內已經沒有這個數,就可以把種類數--了,同理,加也一樣,如果是加上變成1,說明從無到有,種類++;;;;;對于每一個查詢,維護完種類,就把當前種類記入對應的查詢原始標號內,最后依次輸出

算法步驟

  1. 分塊:將數組分成若干塊,每塊大小約為√n。
  2. 排序查詢:按照左端點所在塊的編號為第一關鍵字,右端點為第二關鍵字進行排序。
  3. 移動端點:維護當前區間的左右端點,通過移動端點來處理每個查詢,并統計答案。

?

?這一題就是最基礎的莫隊查詢

    ?

    #include <bits/stdc++.h>
    using namespace std;

    const int maxn = 100010;

    int n, m, block_size;
    int a[maxn], cnt[maxn], ans[maxn];
    int current_ans = 0, curL = 0, curR = 0;

    struct Query {
    ? ? int l, r, idx;
    ? ? bool operator<(const Query& other) const {
    ? ? ? ? if (l / block_size != other.l / block_size)
    ? ? ? ? ? ? return l / block_size < other.l / block_size;
    ? ? ? ? return (l / block_size) % 2 == 0 ? r < other.r : r > other.r;
    ? ? }
    };//利用了奇偶塊進行分塊

    分塊詳解

    莫隊算法的關鍵在于如何排序查詢區間,使得總移動距離最小。普通分塊策略的步驟是:

    分塊:將整個數據序列分成大小為?B?的塊(通常?B ≈ √n

    排序:首先按左端點所在塊的編號排序。。如果左端點在同一塊,則按右端點排序

    可見 ,分塊是為了計算出端點的范圍并打上標記,方便進行排序,進行優化計算?

    bool operator<(const Query& other) const {//重定義<if (l / B != other.l / B)  // 按塊編號排序,B是預先估算的塊大小(因為通常情況大小和數量就是對n開根號,所以怎么理解都行)return l / B < other.l / B;return r < other.r;        // 左在同一塊內按右端點排序
    }

    普通分塊在處理同一區塊內的查詢時,右端點可能需要反復來回移動,導致額外的時間開銷。奇偶分塊優化的關鍵在于:

    偶數塊:右端點按升序排列

    奇數塊:右端點按降序排列

    這樣處理同一區塊內的查詢時,指針移動形成 "之" 字形路徑,減少了來回跳轉的開銷。

    ?如:(還不如不看,自己腦子里過一遍最清晰)

    Q1: [2, 10], Q2: [2, 4], Q3: [2, 7] (左端點都在塊0,偶數塊)
    

    排序后為?Q2 → Q3 → Q1,右指針路徑:4 → 7 → 10,仍需往返。

    但考慮跨塊的情況:

    Q1: [2, 10](塊0), Q2: [5, 8](塊1), Q3: [5, 12](塊1)
    

    排序后:

    偶數塊(塊 0):Q1?[2, 10]

    奇數塊(塊 1):Q3?[5, 12]?→ Q2?[5, 8]

    處理完 Q1 后,右指針在位置 10,接下來處理 Q3,右指針只需擴展到 12;處理 Q2 時收縮到 8。避免了從 10 收縮到 8 再擴展到 12 的往返操作。

    ?

    Query queries[maxn];


    inline int read() {
    ? ? int x = 0, f = 1; char ch = getchar();
    ? ? while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    ? ? while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    ? ? return x * f;
    }

    void add(int pos) {
    ? ? if (++cnt[a[pos]] == 1) current_ans++;//加
    }

    void del(int pos) {
    ? ? if (--cnt[a[pos]] == 0) current_ans--;//減
    }

    int main() {
    ? ? n = read(); m = read();
    ? ? block_size = sqrt(n);
    ? ??
    ? ? for (int i = 1; i <= n; i++)?
    ? ? ? ? a[i] = read();
    ? ??
    ? ? for (int i = 0; i < m; i++) {
    ? ? ? ? queries[i].l = read();
    ? ? ? ? queries[i].r = read();
    ? ? ? ? queries[i].idx = i;
    ? ? }
    ? ??
    ? ? sort(queries, queries + m);
    ? ? for (int i = 0; i < m; i++) {
    ? ? ? ? int L = queries[i].l, R = queries[i].r;
    ? ? ? ??
    ? ? ? ? while (curL > L) add(--curL);
    ? ? ? ? while (curR < R) add(++curR);
    ? ? ? ? while (curL < L) del(curL++);
    ? ? ? ? while (curR > R) del(curR--);//核心,一下一下移動
    ? ? ? ??
    ? ? ? ? ans[queries[i].idx] = (current_ans == (R - L + 1));

    ????????????????//通過和總量判斷,看看里面是不是有重復元素
    ? ? }
    ? ??
    ? ? for (int i = 0; i < m; i++)
    ? ? ? ? puts(ans[i] ? "Yes" : "No");
    ? ??
    ? ? return 0;
    }

    進階一點(真就一點)

    完全在上一題基礎上改進

    僅注解處改變

    #include <bits/stdc++.h>
    using namespace std;

    const int maxn = 50010;

    int n, m, block_size,k;//多了個k。。。
    int a[maxn];
    long long current_ans = 0,ans[maxn];//因為可能很大,開了ll,這里ans們記錄的就是乘方后的維護了
    int cnt[maxn], curL = 1, curR = 0;

    struct Query {
    ?? ?int l, r, idx;
    ?? ?bool operator<(const Query& other) const {
    ?? ??? ?if (l / block_size != other.l / block_size)
    ?? ??? ??? ?return l / block_size < other.l / block_size;
    ?? ??? ?return (l / block_size) % 2 == 0 ? r < other.r : r > other.r;
    ?? ?}
    };
    Query queries[maxn];
    inline int read() {
    ?? ?int x = 0, f = 1; char ch = getchar();
    ?? ?while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    ?? ?while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    ?? ?return x * f;
    }
    void add(int pos) {
    ?? ?if(a[pos]<=k){
    ?? ?current_ans-=cnt[a[pos]]*cnt[a[pos]];
    ?? ?++cnt[a[pos]];
    ?? ?current_ans+=cnt[a[pos]]*cnt[a[pos]];}
    }
    void del(int pos) {
    ?? ?if(a[pos]<=k){
    ?? ?current_ans-=cnt[a[pos]]*cnt[a[pos]];
    ?? ?--cnt[a[pos]];
    ?? ?current_ans+=cnt[a[pos]]*cnt[a[pos]];}//加減法都變成了對乘方的維護,而且判斷題目條件,減少計算開銷
    }

    int main() {
    ?? ?n = read(); m = read();k = read();//k
    ?? ?block_size = sqrt(n);
    ?? ?for (int i = 1; i <= n; i++)
    ?? ??? ?a[i] = read();
    ?? ?
    ?? ?for (int i = 0; i < m; i++) {
    ?? ??? ?queries[i].l = read();
    ?? ??? ?queries[i].r = read();
    ?? ??? ?queries[i].idx = i;
    ?? ?}
    ?? ?sort(queries, queries + m);
    ?? ?for (int i = 0; i < m; i++) {
    ?? ??? ?int L = queries[i].l, R = queries[i].r;
    ?? ??? ?while (curL > L) add(--curL);
    ?? ??? ?while (curR < R) add(++curR);
    ?? ??? ?while (curL < L) del(curL++);
    ?? ??? ?while (curR > R) del(curR--);

    ?? ??? ?ans[queries[i].idx] = current_ans;//把實時計算的乘方和映射到原始序列的數組鋰
    ?? ?}
    ?? ?
    ?? ?for (int i = 0; i < m; i++)
    ?? ??? ?printf("%lld\n",ans[i]);
    ?? ?return 0;
    }

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/bicheng/87007.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87007.shtml
    英文地址,請注明出處:http://en.pswp.cn/bicheng/87007.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    ? Python 高級定制 | 美化 Word 表格邊框與樣式(收貨記錄增強版)

    之前我們完成了 Excel 數據提取、Word 表格寫入與合并&#xff0c;現在繼續 為 Word 表格添加高級樣式 裝扮&#xff0c;包括單元格邊框、背景填色、居中對齊、粗體、高亮行/列等&#xff0c;進一步增強表格的可讀性與專業性。 &#x1f58c;? 樣式設置函數 1. 設置單元格邊框…

    Clickhouse源碼分析-TTL執行流程

    第一種情況&#xff1a;無ttl_only_drop_parts配置 總體示例以及說明 如果沒有ttl_only_drop_parts的配置&#xff0c;過期數據的刪除&#xff08;這里是刪除&#xff0c;是將過期的數據從這個part刪除&#xff0c;并將過期的數據構成一個part&#xff0c;這個過期的part標記…

    elementui修改radio字體的顏色和圓圈的樣式

    改完 <div class"choose"><el-radio-group v-model"radioNum"><el-radio label"1" size"large">Option 1</el-radio><el-radio label"2" size"large">Option 2</el-radio>&l…

    力扣3381. 長度可被 K 整除的子數組的最大元素和

    由于數據范圍是2*10^5所以必然是遍歷一次&#xff0c;子數組必定要用到前綴和&#xff0c;之前的題目中總是遇到的是子數組的和能不能被k整除&#xff0c;而這里不一樣的是子數組的長度能不能被k整除&#xff0c;如果單純的枚舉長度必定超時&#xff0c;而看看題解得出的思路&a…

    基于SSM的勤工助學系統的設計與實現

    第1章 摘要 基于SSM框架的勤工助學系統旨在為學生、用工部門和管理員提供高效便捷的管理平臺。系統包括學生端、用工部門端和管理員端&#xff0c;涵蓋了從崗位發布、申請審核、工時記錄、薪資管理到數據統計等完整的功能需求。 學生可以通過系統首頁瀏覽最新的崗位信息和公告&…

    2025年06月30日Github流行趨勢

    項目名稱&#xff1a;twenty 項目地址 URL&#xff1a;https://github.com/twentyhq/twenty項目語言&#xff1a;TypeScript歷史 star 數&#xff1a;31,774今日 star 數&#xff1a;1,002項目維護者&#xff1a;charlesBochet, lucasbordeau, FelixMalfait, Weiko, bosiraphae…

    creo 2.0學習筆記

    Creo軟件從入門到精通——杜書森 1.1 Creo基本建模過程介紹 新建-零件-改名稱-取消使用默認模板&#xff0c;是因為默認的是英制尺寸&#xff0c;自定義可選擇mmns_part_solid&#xff0c;模板主要是設置模型的單位拉伸-選取FRONT-點擊草繪視圖&#xff0c;可進行草繪旋轉——…

    ZNS初步認識—GPT

    1. ZNS SSD 的基本概念 Zoned Namespace (ZNS): ZNS 是一種新的NVMe接口規范&#xff0c;它將SSD的邏輯塊地址空間劃分為多個獨立的、固定大小的“區域”&#xff08;Zones&#xff09;。區域 (Zone): ZNS SSD 的基本管理單元。每個區域都有自己的寫入指針&#xff08;write p…

    【seismic unix生成可執行文件-sh文件】

    Shell腳本文件&#xff08;.sh文件&#xff09;簡介 Shell腳本文件&#xff08;通常以.sh為擴展名&#xff09;是一種包含Shell命令的文本文件&#xff0c;用于在Unix/Linux系統中自動化執行任務。它由Shell解釋器&#xff08;如Bash、Zsh等&#xff09;逐行執行&#xff0c;常…

    Debezium日常分享系列之:在 Kubernetes 上部署 Debezium

    Debezium日常分享系列之&#xff1a;在 Kubernetes 上部署 Debezium 先決條件步驟部署數據源 (MySQL)登錄 MySQL db將數據插入其中部署 Kafka部署 kafdrop部署 Debezium 連接器創建 Debezium 連接器 Debezium 可以無縫部署在 Kubernetes&#xff08;一個用于容器編排的開源平臺…

    利潤才是機器視覺企業的的“穩定器”,機器視覺企業的利潤 = (規模經濟 + 技術差異化 × 場景價值) - 競爭強度

    影響機器視覺企業盈利能力的關鍵因素。這個公式本質上反映了行業的核心動態:利潤來自成本控制(規模化效應)和差異化優勢(技術壁壘與場景稀缺性的協同),但被市場競爭(內卷程度)所侵蝕。下面我將一步步拆解這個公式,結合機器視覺行業的特點(如工業自動化、質檢、安防、…

    EPLAN 中定制 自己的- A3 圖框的詳細指南(一)

    EPLAN 中定制 BIEM - A3 圖框的詳細指南 在智能電氣設計領域&#xff0c;圖框作為圖紙的重要組成部分&#xff0c;其定制的規范性和準確性至關重要。本文將以北京經濟管理職業學院人工智能學院的相關任務為例&#xff0c;詳細介紹在 EPLAN 軟件中定制 BIEM - A3 圖框的全過程…

    macbook開發環境的配置記錄

    前言&#xff1a;好多東西不記錄就會忘記 git ssh配置 當我們的沒有配置git ssh的時候&#xff0c;使用ssh下載的時候會顯示報錯“make sure you have the correct access rights and respository exits" 如何解決&#xff0c;我們先在命令行檢查檢查一下用戶名和郵箱是…

    GitLab 18.1 高級 SAST 已支持 PHP,可升級體驗!

    GitLab 是一個全球知名的一體化 DevOps 平臺&#xff0c;很多人都通過私有化部署 GitLab 來進行源代碼托管。極狐GitLab 是 GitLab 在中國的發行版&#xff0c;專門為中國程序員服務。可以一鍵式部署極狐GitLab。 學習極狐GitLab 的相關資料&#xff1a; 極狐GitLab 官網極狐…

    [學習]M-QAM的數學原理與調制解調原理詳解(仿真示例)

    M-QAM的數學原理與調制解調原理詳解 QAM&#xff08;正交幅度調制&#xff09;作為現代數字通信的核心技術&#xff0c;其數學原理和實現方法值得深入探討。本文將分為數學原理、調制解調原理和實現要點三個部分進行系統闡述。 文章目錄 M-QAM的數學原理與調制解調原理詳解一、…

    圖書管理系統練習項目源碼-前后端分離-使用node.js來做后端開發

    前端學習了這么久了&#xff0c;node.js 也有了一定的了解&#xff0c;知道使用node也可以來開發后端&#xff0c;今天給大家分享 使用node 來做后端&#xff0c;vue來寫前端&#xff0c;做一個簡單的圖書管理系統。我們在剛開始學習編程的時候&#xff0c;需要自己寫大量的項目…

    【甲方安全視角】企業建設下的安全運營

    文章目錄 一、安全運營的概念與起源二、安全運營的職責與定位三、安全運營工程師的核心能力要求四、安全運營的典型場景與應對技巧1. 明確責任劃分,避免“醫生做保姆”2. 推動機制:自下而上 vs. 自上而下3. 宣傳與內部影響力建設五、安全運營的戰略意義六、為何需要安全原因在…

    03認證原理自定義認證添加認證驗證碼

    目錄 大綱 一、自定義資源權限規則 二、自定義登錄界面 三、自定義登錄成功處理 四、顯示登錄失敗信息 五、自定義登錄失敗處理 六、注銷登錄 七、登錄用戶數據獲取 1. SecurityContextHolder 2. SecurityContextHolderStrategy 3. 代碼中獲取認證之后用戶數據 4. 多…

    IPLOOK 2025上半年足跡回顧:連接全球,步履不停

    2025年上半年&#xff0c;IPLOOK積極活躍于全球通信舞臺&#xff0c;足跡橫跨亞洲、歐洲、非洲與北美洲&#xff0c;我們圍繞5G核心網、私有網絡、云化架構等方向&#xff0c;向來自不同地區的客戶與合作伙伴展示了領先的端到端解決方案&#xff0c;深入了解各地市場需求與技術…

    【Kafka】docker 中配置帶 Kerberos 認證的 Kafka 環境(全過程)

    1. 準備 docker 下載鏡像 docker pull centos/systemd&#xff0c;該鏡像是基于 centos7 增加了 systemd 的功能&#xff0c;可以更方便啟動后臺服務 啟動鏡像 使用 systemd 功能需要權限&#xff0c;如果是模擬 gitlab services 就不要使用 systemd 的方式啟動 如果不使用 s…