C 學習筆記 解析莫隊演算法

2021-09-25 08:45:49 字數 1887 閱讀 4330

集訓隊隊長莫濤 and 提莫隊長 are coming ......

相傳是國家集訓隊隊長莫濤在一次比賽中想出的演算法,所以稱作莫隊演算法(提莫隊長??),類似於暴力維護,但卻非常巧妙,而且據說是可以對區間進行各種操作,幾乎萬能哎,還有各種改進版本,如帶改莫隊,樹上莫隊 and so on

我們先想象出兩個指標curl和curr,以及我們要查詢的區間[ l , r ]

當遍歷到這種情況時,我們只需要將curl向左移動,以 o( 1 ) 的時間複雜度得到新的區間[ l , curr ]

再將curr向左移動,得到目標區間 [ l , r ]

但如果多組詢問,且每組詢問的l和r跨度極大呢

對於乙個長度為n的區間,將他分為

如果所處塊相等,則按右端點大小排序,否則按左端點大小排序

bool cmp( node x , node y ) //cnt為塊數
經過這種精巧的分塊思想排序,就可以大大降低時間複雜度了

先來乙個例題

乙個長度為n的區間,m個查詢,問在區間[ l , r ]內有多少個數的出現次數為 k 

直接上**(可以當做模板)

後面重點講解(敲黑板,使勁敲的那種重點)

#include #include #include #include #include #define ll long long

using namespace std;

ll ans[50005] , ans_now ;//儲存答案

int n , m , k , cnt ;//cnt表示塊數

int curl = 1 , curr = 0 , a[50005] ;

int c[50005] ;//儲存每個數出現次數

struct node que[50005];

bool cmp( node x , node y )

void add( int x )

void dele( int x )

int main()

sort( que+1 , que+m+1 , cmp );

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

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

printf("%lld\n", ans[i] );

}

重點來了,重中之重

為什麼在移動指標時,對區間修改一會先++,一會後++,花裡胡哨的,有什麼用???

大大的有用啊

如,dele( ++x ) 是先將x+1,再執行dele裡的操作而 dele(x++)是先執行dele裡的操作,再將x+1

當 curl < l 時,curl向右移動到curl+1,要刪除的是curl,所以是 dele( curl++ )

當 curl > l 時,curl向左移動到curl-1,要新增的是curl-1,所以是 add( --curl )

然後右端點同理

提莫隊長正在待命。。。

莫隊演算法學習筆記(一) 普通莫隊

前言 在學習莫隊演算法之前,我一直以為這是乙個很高深的演算法。實際上,它就是乙個很高深的演算法 這個演算法玄學地將分塊與暴力兩大演算法實現了二合一,從而打造出了乙個時間複雜度為o n n o n sqrt n o nn 的求解多個區間詢問的離線演算法。具體介紹 首先,我們以詢問中l ll所在的區間為...

莫隊演算法學習筆記(三) 樹上莫隊

樹上莫隊的核心思想,就是將一棵樹轉化成乙個序列,然後用普通莫隊來搞。以一棵樹為例 要想對這棵樹進行樹上莫隊,我們第一步就是用乙個 s 陣列把它的括號序存下來 id 12 3456 78910 1112 1314 1516 s 12 4788 7455 2366 31 同時,我們用 i 陣列儲存每個數...

莫隊演算法學習筆記

莫隊演算法 有時候我們經常會碰到這樣一類問題 給定n和n個數etc,然後給出m組區間詢問 l,r 要求對所有詢問區間給出答案。然後發現這類題通常有乙個很好的性質就是,如果你知道了 l,r 的答案,就可以o 1 或者o lgn 再大就有點玄了 的知道 使得根據第i個區間 li,ri 的答案拓展到第i ...