優雅的區間問題暴力 莫隊演算法

2022-09-18 09:03:21 字數 1307 閱讀 2325

對dalao口中可以\(o(n^})\)區間內絕大部分無修改離線問題的莫隊演算法,一直處於「好騎」的狀態,最近終於找到了學習的機會,其實感覺,這著實是乙個優雅的暴力。

莫隊演算法的大前提,是可以利用已知的[l,r]內的答案,直接得到[l,r+1],[l+1,r],[l-1,r],[l,r-1]上的答案。

以下內容預設上述轉移為o(1)的。

在此基礎上,顯然的,作為兩次詢問[l,r],[l',r']之間的轉移,時間花費為o(|l-l'|+|r-r'|)。

我們將每次詢問看做二維平面上的點,則所有詢問間轉移的花費就為在沿著這個平面上最小直線斯坦納樹做的花費,不管你會不會,反正我是不會這種做法。

因此,我們有個良好的替代品,分塊。

將每個詢問按照[l->pos,r]的順序依次排序,l->pos指的是l屬於的區塊編號,按照排序後的順序去做,顯然是相對較優的做法之一。

分析一下時間複雜度:

考慮分塊大小為x的情況:

考慮左指標移動次數:

若在塊內移動,每次最多移動\(o(x)\)次,最多q次,時間複雜度為\(o(xq)\);

若在塊外移動,每次最多移動\(o(n/x+x)\)次,最多從塊1移動到塊n/x,每次最多加上x次塊內移動,時間複雜度為o(n).

當q較大時,總複雜度可以近似看為\(o(xq)\).

考慮右指標移動次數:

若在塊內移動,每次最多移動\(o(x)\)次,最多q次,時間複雜度為\(o(xq)\);

考慮塊外移動,最壞情況由n到1,總共經過n/x塊,最壞時間複雜度為\(o(nq/x)\);

總時間複雜度視x不定,但當x取\(n^}\)時,最壞時間複雜度最穩定,穩定於\(o(qn^})\);

結合上述論述可以發現,為了保證右端點的移動的時間複雜度穩定,x取\(o(n^})\)是最優的選擇,故總時間複雜度為\(o(qn^})\)。

當n與q為同數量級時,可近似看為\(o(n^})\)。

接下來貼一下模板,模板題傳送門。

#include #include #include #define r register

#define mn 50005

#define ll long long

int n,m,cnt[mn],col[mn];ll ans[mn],sum;

struct query

int main()std::sort(query+1,query+m+1);

for (r int i=1,l=1,r=0; i<=m; ++i)for (r int i=1; i<=m; ++i) printf("%lld\n",ans[i]);

}

莫隊 優雅的暴力演算法

例題 牛客暑期訓練營 j 題意描述 輸入一串整數 n 1e5 對於每個詢問 i,j 輸出a 1 a i 以及a j a n 裡數字的種類數,詢問一共q個 n 思路分析 暴力解法,即對於每個詢問均通過遍歷尋找答案,會令複雜度高達o n 2 考慮對其進行優化。我們知道對於詢問 i,j 去掉i對結果造成的...

莫隊演算法 普通莫隊 智慧型暴力例題模板

1 基礎莫隊演算法2.莫隊演算法實現 莫隊演算法把排序做了簡單的修改,就把暴力法的複雜度從o mn 提高到o n n 1 暴力法的排序 把查詢的區間按左端點排序,如果左端點相同,再按右端點排序。莫隊演算法的排序 把陣列分塊 分成 n塊 然後把查詢的區間按左端點所在塊的序號排序,如果左端點的塊相同,再...

處理區間問題之樹狀陣列與莫隊演算法

感覺我直到前兩天才算是真正學會用樹狀陣列啊囧。有一類離線的區間詢問問題,可以有以下解法 我暫時會這麼多 離線 樹狀陣列 線段樹 莫隊演算法 線段樹先不說了,好久沒寫過了,而且本文的標題是樹狀陣列與莫隊囧。用樹狀陣列的關鍵在於,每次插入乙個點或者刪除乙個點要維護什麼東西,一般是插入右端點刪除左端點,維...