1 基礎莫隊演算法2.莫隊演算法實現
莫隊演算法把排序做了簡單的修改,就把暴力法的複雜度從o(mn)提高到o (n√n)
(1)暴力法的排序:把查詢的區間按左端點排序,如果左端點相同,再按右端點排序。
莫隊演算法的排序:把陣列分塊(分成√n塊),然後把查詢的區間按左端點所在塊的序號排序,如果左端點的塊相同,再按右端點排序(注意不是按右端點所在的塊排序)。
除了排序不一樣,莫隊演算法和暴力法的其他步驟完全一樣。
(2)如果我們知道區間[l,r],就能在o(1)求出[l−1,r],[l+1,r],[l,r−1],[l,r+1]的話,那就可以用莫隊演算法了。
所以我們要解決的問題只有兩個
①如何將讀入的查詢排序。
bool
cmp(node a,node b)
void
add(
int x)
//擴大區間時(l左移或r右移),增加數x出現的次數
void
del(
int x)
//縮小區間時(l右移或r左移),減少數x出現的次數
for(
int i=
1;i<=m;i++
)//莫隊演算法核心
3.小優化:奇偶性排序
奇數塊從小到大,偶數塊從大到小和奇數塊從大到小,偶數塊從小到大都是可行的,下面的例題我使用的是前者。
這樣能快是因為右指標移到右邊後不用再跳回左邊,而跳回左邊後處理下乙個塊又要跳回右邊,這樣能減少一半操作,理論上能快一倍。
下面是一道例題
題目描述
hh 有一串由各種漂亮的貝殼組成的項鍊。hh 相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。hh 不斷地收集新的貝殼,因此,他的項鍊變得越來越長。有一天,他突然提出了乙個問題:某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答……因為項鍊實在是太長了。於是,他只好求助睿智的你,來解決這個問題。
輸入輸出格式
輸入格式:
第一行:乙個整數n,表示項鍊的長度。
第二行:n 個整數,表示依次表示項鍊中貝殼的編號(編號為0 到1000000 之間的整數)。
第三行:乙個整數m,表示hh 詢問的個數。
接下來m 行:每行兩個整數,l 和r(1 ≤ l ≤ r ≤ n),表示詢問的區間。
輸出格式:
m 行,每行乙個整數,依次表示詢問對應的答案。
輸入輸出樣例
輸入樣例#1:
61 2 3 4 3 5
31 2
3 52 6
輸出樣例#1:22
4說明資料範圍:
對於100%的資料,n <= 500000,m <= 500000。
#include
#include
#include
#define maxn 1000000+10
using
namespace std;
struct node
q[maxn]
;int cnt[maxn]
;//統計數字i出現的次數
int pos[maxn]
;//儲存第i個元素所在的塊
int ans[maxn]
;//記錄答案
int a[maxn]
;//儲存序列
int ans=0;
bool
cmp(node a,node b)
void
add(
int x)
//擴大區間時(l左移或r右移),增加數x出現的次數
void
del(
int x)
//縮小區間時(l右移或r左移),減少數x出現的次數
intmain()
cin>>m;
for(
int i=
1;i<=m;i++
)sort
(q+1
,q+m+
1,cmp)
;int l=
1,r=0;
//左右指標的初始值
for(
int i=
1;i<=m;i++
)//莫隊演算法核心
for(
int i=
1;i<=m;i++
)return0;
}
莫隊總結 莫隊例題
假設我們已知區間 l,r,需要計算的區間為 l,r,由於 l 和 r分別只能單步轉移,所以需要的時間複雜度為 l l r r 相當於把兩個區間分別看成是平面上的兩個整點p1 l,r 和p2 l,r 兩點之間的轉移開銷為兩點之間的曼哈頓距離。連線所有點的最優方案為一棵樹,那麼整體的時間複雜度就是這棵樹...
莫隊講解 普通莫隊
結束了分塊,我們來講下莫隊。據我所知,莫隊能解決一切區間問題,除了翻轉。因為它就是個暴力 其實這兩者的關係並不大。僅僅是時間複雜度一樣而已。我們把原序列分成 n塊 好像就是這裡相同 這裡說的序列是查詢序列l r,並不是讀入的a i 之後我們把序列排序 按照第一關鍵字為左端點所在的塊的大小,如果相同就...
莫隊演算法學習筆記(一) 普通莫隊
前言 在學習莫隊演算法之前,我一直以為這是乙個很高深的演算法。實際上,它就是乙個很高深的演算法 這個演算法玄學地將分塊與暴力兩大演算法實現了二合一,從而打造出了乙個時間複雜度為o n n o n sqrt n o nn 的求解多個區間詢問的離線演算法。具體介紹 首先,我們以詢問中l ll所在的區間為...