基礎莫隊演算法

2022-08-29 05:24:09 字數 2192 閱讀 6377

最好是會一點線段樹,不會也沒有關係

我們都知道,維護區間資訊的時候通常會用到各種線段樹,因為其本身具有的性質可以在很快的速度內完成各種操作。但是這是基於我們上推(pushup)和下推(pushdown)這兩種操作可以在o(1)的時間內完成的基礎。如果這兩個操作本身需要的時間不是常數級別的化我們可能需要考慮其他的方法。莫隊演算法可以有效地解決一部分這樣的問題。更加精確地來講,普通莫隊演算法可以解決的問題有以下兩種特徵:

只有查詢,沒有修改

從區間\([ l , r]\)拓展到區間\([ l\pm1,r\pm1]\)的時間消耗是常數級別的

當然莫隊演算法還有很多其他的變種,類似於樹上莫隊,代修莫隊等等。這裡我們只介紹最簡單的基礎莫隊。

簡單來講,莫隊演算法的思想就是用特殊的順序對詢問進行排序使得程式執行時間加快。

打個比方,我們現在要維護區間和,並且假設大家都沒學過字首和,樹狀陣列和線段樹,那麼我們能想道的最樸素的演算法就是對於每乙個詢問都老老實實地從 l 遍歷到 r 。但是我們發現了乙個問題,對於兩組詢問, \([l_1,r_1]\)和\([l_2,r_2]\)來講,如果出現了下圖的情況:

我們是沒必要在第二個詢問的時候重新遍歷的,因為區間 \([l_1,r_2]\)的答案實際上已經包含在了\([l_1,r_]\),也就是第一次詢問裡面了,並且從\(l_1\)擴充套件到\(l_2\),\(r_1\)擴充套件到\(r_2\)的時間消耗可能比較低(因為從位置\(i\)擴充套件答案到\(i\pm1\)的位置的時間消耗是o(1)的)。這就是莫隊演算法的思想,還是比較簡單的。

那麼可能有人要問了,如果我們的查詢區間是類似於: \([1,2]\),\([n-1,n]\),\([1,3]\),\([n-2,n]\)這樣的,相鄰詢問跨度很大並且沒有交集的情況該怎麼半呢?這裡我們可以對詢問進行排序。可以把每乙個和詢問抽象成平面上面的兩個點,那麼詢問\([l_1,r_1]\)到\([l_2,r_2]\)的時間消耗就是\(abs(l_1-l_2)+abs(r_1-r_1)\),也就是這兩個點之間的曼哈頓距離。那麼我們對詢問的排序也就很明顯了,就是求這幅圖的最小曼哈頓距離生成樹。

但是這麼寫的化碼量實在是有一些大(計算幾何題的**複雜程度大家肯定也是有目共睹的),那麼我們能不能找到乙個不錯的替代品呢?

我們簡單地對區間進行分塊,然後對於左區間在同一塊內的群問按照右區間從小到大排序,否則就按照左區間進行排序,這樣的化就可以有效地加快程式執行速度。

例題: 小b的詢問

簡單來說就是要你維護每乙個數字在區間\([l,r]\)內部出現次數的平方和。

用線段樹是會t的,但是我們新加乙個數到答案裡面的時間是常數的,所以我們可以考慮用莫隊

首先我們需要把詢問給儲存起來,最好還是另外存乙個k來表示第k個詢問,因為最後輸出的時候還是會檢查你的順序的

struct qq[maxn];
然後就正常讀入啊什麼的,順便分個塊

scanf("%d %d %d",&n,&m,&k);

int siz=n/sqrt(m*2/3);//似乎說是這麼分會快一點

for(int i=1;i<=n;i++)

for(int i=1;i<=m;i++)

接著寫一下排序的cmp函式:

bool cmp(q a,q b)
這裡的add函式和sub函式就是計算新增加/減少的乙個數對答案的貢獻的函式,後面一定要記得按照每乙個詢問的k值來村答案

void add(int n)

void sub(int n)

最後再輸出一下就好了

ac**全放送:

#include using namespace std;

const int maxn=1e5;

struct qq[maxn];

int a[maxn],cnt[maxn],pos[maxn],n,m,k,ans[maxn],rsl;

bool cmp(q a,q b)

for(int i=1;i<=m;i++)

}

這裡我們還可以用乙個小技巧,就是如果兩個\(l\)所在的塊是奇數塊的化\(r\)就要從小到大排序,如果是偶數塊的化就從大到小。這樣的化對於在同乙個塊內的詢問我們就可以在回來的之後順便計算下一次詢問的值了。

莫隊演算法基礎與練習

gym卡了莫隊,於是趁這個機會學一下莫隊 莫隊的核心是分塊排序,這種特殊的排序方法將任務按排序後的順序完成,可以在解決絕大多數無修改的離線區間問題中極大的優化時間 優化了sqrt n 左右 nbut 1457 題意 n個數,尋問10000次,任意區間內的相等數的次數的立方和。題解 將n個數離散化後,...

樹上莫隊演算法

繼續回來寫部落格 記錄點有意思的題目什麼的。貌似寫過這個的沒多少人 所以我也記錄一點。首先序列上的莫隊大家都應該很熟悉了 那麼樹上的莫隊要怎麼搞呢?先來看個題目 spoj cot2 求樹上兩點間路徑上有多少個不同的點權。序列上的莫隊是把詢問按照左端點分塊了 可是樹上沒有左端點,怎麼辦呢?我們把樹分塊...

模板 莫隊演算法

題意 給定乙個大小為n的陣列,陣列中所有元素的大小 n。你需要回答m個查詢。每個查詢的形式是l,r,k。你需要回答在範圍 l,r 中至少重複k次的數字的個數。n,m 100000 誒,這題卡了好久,tle,中間棄了一段,然後今天學弟學莫隊,拿出這個題,他也沒什麼想法,然後我頓時退一步海闊天空了。最開...