CDQ分治小結

来源:https://www.cnblogs.com/zwfymqz/archive/2018/12/12/10111650.html
-Advertisement-
Play Games

CDQ分治小結 warning:此文僅用博主複習使用,初學者看的話後果自負。。 複習的時候才發現以前根本就沒寫過這種東西的總結,簡單的扯一扯 cdq分治的經典應用就是解決偏序問題 比如最經典的三維偏序問題 給出$n$個數,每個數$i$,有三個屬性$a_i, b_i, c_i$,現在我們要統計對於每個 ...


CDQ分治小結

warning:此文僅用博主複習使用,初學者看的話後果自負。。

複習的時候才發現以前根本就沒寫過這種東西的總結,簡單的扯一扯

cdq分治的經典應用就是解決偏序問題

比如最經典的三維偏序問題

給出\(n\)個數,每個數\(i\),有三個屬性\(a_i, b_i, c_i\),現在我們要統計對於每個\(i\)\(a_j \leqslant a_i, b_j \leqslant b_i, c_j \leqslant c_i\)的個數

顯然我們可以先把所有數都按\(a_i\)排序一遍,這樣考慮每個位置\(i\)的時候只需要考慮它前面的貢獻即可

接下來我們遞歸處理區間\([1, N]\)

設分治中心為\(mid\),cdq分治的主要思想遞歸處理每一段區間,只考慮過分治中心的貢獻。

同時,我們採用歸併排序的思想,保證每一次統計答案的時候區間\([l, mid]\)\([mid +1, r]\)內的元素的\(b_i\)都是相對有序的

這樣我們只需要用兩個指針掃一遍,同時用樹狀數組來維護一下\(c_i\)即可

好像說的挺抽象的,貌似直接看代碼會好很多?

void CDQ(int l, int r) {
    if(l >= r) return ;//區間不合法
    int mid = l + r >> 1;
    CDQ(l, mid); CDQ(mid + 1, r);//遞歸下去處理子區間,處理完之後保證區間內的bi相對有序
    int nl = l, nr = mid + 1, top = l - 1, sum = 0;//使用兩個指針來歸併本區間
    while(nl <= mid || nr <= r) {//st數組記錄的時把兩端區間按bi大小合併後的值
        if((nr > r) || (nl <= mid && A[nl].b <= A[nr].b)) T.add(A[nl].c, A[nl].w), st[++top] = A[nl++];//用樹狀數組維護ci的貢獻
        else A[nr].id += T.Query(A[nr].c ), st[++top] = A[nr++];//直接查詢即可
    }
    for(int i = l; i <= mid; i++) T.add(A[i].c, -A[i].w);//把左邊區間的影響消除
    for(int i = l; i <= r; i++) A[i] = st[i];//按bi排序
}

然而有一種非常噁心的情況:即\(a_i = a_j, b_i = b_j, c_i = c_j\)

他們內部的貢獻往往是不好考慮的,一個最直觀的想法是直接把這些相同的數看成一個,統計答案的時候直接加上他們的數量即可

模板

洛谷P3810 【模板】三維偏序(陌上花開)

#include<bits/stdc++.h>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
using namespace std;
const int MAXN = 2e5 + 10;
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    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;
}
char obuf[1<<24], *O=obuf;
void print(int x) {
    if(x > 9) print(x / 10);
    *O++= x % 10 + '0';
}
int N, ans[MAXN];
struct Array {
    int a, b, c, id, w;
    bool operator == (const Array &rhs) const {
        return a == rhs.a && b == rhs.b && c == rhs.c;
    }
    bool operator < (const Array &rhs) const {
        return(a == rhs.a ? (b == rhs.b ? c < rhs.c : b < rhs.b) : a < rhs.a);
    }
}A[MAXN], st[MAXN];
struct Node {
#define lb(x) (x & (-x))
    int T[MAXN], Lim;
    void add(int x, int v) {
        while(x <= Lim) T[x] += v, x += lb(x);
    }
    int Query(int x) {
        int ans = 0;
        while(x) ans += T[x], x -= lb(x);
        return ans;
    }
}T;
void CDQ(int l, int r) {
    if(l >= r) return ;
    int mid = l + r >> 1;
    CDQ(l, mid); CDQ(mid + 1, r);
    int nl = l, nr = mid + 1, top = l - 1, sum = 0;
    while(nl <= mid || nr <= r) {
        if((nr > r) || (nl <= mid && A[nl].b <= A[nr].b)) T.add(A[nl].c, A[nl].w), st[++top] = A[nl++];
        else A[nr].id += T.Query(A[nr].c ), st[++top] = A[nr++];
    }
    for(int i = l; i <= mid; i++) T.add(A[i].c, -A[i].w);
    for(int i = l; i <= r; i++) A[i] = st[i];
}
int main() {
    N = read(); T.Lim = read();
    for(int i = 1; i <= N; i++) A[i].a = read(), A[i].b = read(), A[i].c = read(), A[i].w = 1;
    stable_sort(A + 1, A + N + 1);
    int num = 1;
    for(int i = 2; i <= N; i++){
        if(A[i] == A[num]) A[num].w++; 
        else A[++num] = A[i];
    }
    CDQ(1, num);
    for(int i = 1; i <= num; i++) ans[A[i].id + A[i].w - 1] += A[i].w;
    for(int i = 0; i < N; i++) print(ans[i]), *O++ = '\n';
    fwrite(obuf, O-obuf, 1 , stdout);
    return 0;
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 開心一刻 今天上課不小心睡著了,結果被老師叫起來回答問題,這是背景。無奈之下看向同桌尋求幫助,同桌小聲說到選C,結果周圍的人都說選C,向同桌投去一個感激的眼神後大聲說道選C。剛說完教室就笑開了,老師一臉恨鐵不成鋼的表情說選你個頭,我叫你翻譯文言文你選C!你出去,你給我出去。看著同桌擠眉弄眼的表 ...
  • 什麼是scrapy? scrapy是一個為了爬去網站數據,提取結構性數據而編寫的應用框架,我們只需要實現少量的代碼,就能夠快速的抓取 scrapy使用了 Twisted 非同步網路框架,可以加快我們的下載速度 非同步和非阻塞的區別 非同步:調用在發佈之後,這個調用就直接返回,不管有無結果 非阻塞:關註的是 ...
  • 過濾器模式 一、什麼是過濾器模式   過濾器模式(Filter Pattern),這種模式允許開發人員使用不同的標準來過濾一組對象,通過邏輯運算以解耦的方式把它們連接起來。這種類型的設計模式屬於結構型模式,它結合多個標準來獲得單一標準。 二、具體實現 1、主要角色 過濾對象:需要 ...
  • 一、簡介 以下引用自百度百科 Matplotlib 是一個 Python 的 2D繪圖庫,它以各種硬拷貝格式和跨平臺的互動式環境生成出版質量級別的圖形 。 通過 Matplotlib,開發者可以僅需要幾行代碼,便可以生成繪圖,直方圖,功率譜,條形圖,錯誤圖,散點圖等。 二、流程 1. 明確要研究的問 ...
  • 本文將介紹使用框架mybatis開發原始Dao層來對一個對資料庫進行增刪改查的案例。 本次使用的mybatis版本為mybatis-3.2.7,開發工具為eclipse,資料庫為mysql,jdk版本jdk1.8.0_151。 1、首先,使用eclipse新建一個java工程,在lib目錄下加入my ...
  • 在c++中我們很容易遇到字元串的分割處理問題,這種問題通常比較容易,但由於我比較菜,花費了一定時間去思考一個和字元串相關的題,該題的大概思路是利用取模運算後,將得到的單個字元進行分析,主要考察到了字元串的合併操作,明日計劃30學習c++。 ...
  • ss -l ...
  • Python基礎知識(30):圖形界面(Ⅰ) Python支持多種圖形界面的第三方庫:Tk、wxWidgets、Qt、GTK等等 Tkinter可以滿足基本的GUI程式的要求,此次以用Tkinter為例進行GUI編程 一、編寫一個GUI版本的“Hello, world!” 本人使用的軟體是pycha ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...