神犇mx:你是**來的弱菜?你是不是上次noip爆0的那個大弱雞xyz32768?
xyz32768:我就是那個noip2017寫炸兩題的蒟蒻,的確是大弱雞。
神犇mx:我還聽說你連莫隊都不會……你恐怕明年noip連400都沒有了。
xyz32768:莫……莫隊?
神犇mx:就是這樣:乙個
n n
個數的序列,每次詢問區間……
xyz32768:反正我也不懂,算了,我已經做好了noip2018爆0的準備了。
乙個問題:乙個
n' role="presentation" style="position: relative;">n
n個數的序列,每次詢問區間[l
,r] [l,
r]
內出現了多少個不同的數。
乙個想法是線段樹,但是也很容易看出,這裡線段樹上維護的內容沒有合併性質,因此線段樹不可做。而對於區間的內容沒有合併性質的問題,可以用下面介紹的莫隊演算法解決。
1、不包含修改操作。
2、題目允許離線,也就是允許在所有詢問全部讀入完之後回答所有詢問。
3、不同區間的結果可以互相計算得出。怎麼理解這個條件呢?
就上面的問題而言,如果上一次已經回答了[l
,r] [l,
r]
區間的答案,並且已經存下了[l
,r] [l,
r]
區間裡的所有數值的出現次數,那麼如果下面要詢問[l
,r+1
] [l,
r+1]
的結果,就只要把右指標
r r
向右移乙個單位,並將序列的第r+
1' role="presentation" style="position: relative;">r+1
r+1個數的出現次數++
+
+,同時維護當前的答案,也就是說,如果第r+
1 r+1
個數在[l
,r] [l,
r]
區間內沒有出現,則當前答案++
+
+。同樣,對於[l
,r−1
],[l
−1,r
][l+
1,r]
[ l,
r−1]
,[l−
1,r]
[l+1
,r
]以及其他任何的區間都可以在上乙個詢問的基礎上,通過
l l
和r' role="presentation" style="position: relative;">r
r移動指標來求得下乙個詢問的答案。如果滿足這樣的條件,就是說不同區間的結果可以互相計算得出。
可以看出,一次移動指標是o(
1)o (1
)的。於是想到可以回答第
1 1
個詢問之後,不斷地移動指標,乙個乙個移動到後面將要回答的所有區間。
莫隊演算法的主要思想就是這樣。同時,莫隊演算法利用了可以離線的條件,將詢問按照合理的順序進行求解,實現了o(
nn)' role="presentation" style="position: relative;">o(n
n−−√
)o(n
n)的複雜度。
首先,將序列分塊,即分成n−
−√n
塊,每個塊的大小為n−
−√n
。 然後,就將詢問按照左端點所在的塊為第一關鍵字,右端點的位置為第二關鍵字進行從小到大排序,這樣,就能像上面那樣不斷移動指標,可以達到o(
nn−−
√)o (n
n)
的複雜度。
不妨把左端點在同乙個塊內的詢問分成一組。
先考慮右端點的移動次數。由於在同一組詢問內的右端點是遞增的,所以在同一組內,右端點移動了o(
n)o (n
)次。同時在跨越兩個組時,右端點的移動次數也是o(
n)o (n
),即右端點一共移動了o(
nn−−
√)o (n
n)
次。 再考慮左端點的移動次數。可以看出,在同一組詢問內,左端點一次移動的次數為o(
n−−√
) o(n
)次。
再加上在跨越兩個組時,左端點的移動次數也是o(
n−−√
) o(n
),因此左端點一共移動了o(
nn−−
√)o (n
n)
次。複雜度得證。
hljs cpp">#include
#include
#include
#include
using
namespace
std;
const
int n = 5e4 + 5, m = 1e6 + 5, l = 2e5 + 5;
int n, a[n], ans[n], cnt[m];
struct cyx
} ask[l];
int main()
sort(ask + 1, ask + m + 1);
int tot = 0, sl = 0, sr = 0;
for (i = 1; i <= m; i++)
for (i = 1; i <= m; i++) printf("%d\n", ans[i]);
return
0;}
1、[bzoj1878][sdoi2009]hh的項鍊:
2、[bzoj2038][2009國家集訓隊]小z的襪子:
3、[bzoj3236][ahoi2013]作業:
4、[bzoj4540][hnoi2016]序列:
5、[bzoj4542][hnoi2016]大數:
莫隊演算法學習筆記(一) 普通莫隊
前言 在學習莫隊演算法之前,我一直以為這是乙個很高深的演算法。實際上,它就是乙個很高深的演算法 這個演算法玄學地將分塊與暴力兩大演算法實現了二合一,從而打造出了乙個時間複雜度為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 ...