莫隊演算法被稱為優雅的暴力,是一種 毒瘤暴力的 區間操作演算法。初學莫隊,記錄一下思想。
對於多個區間查詢[l,r]這類問題,可以離線操作,常規做法還有對左區間或者右區間從小到大排序,讓左指標或者右指標只走一遍,有效降低時間複雜度。但是遇到[1,1000000],[2,3],[3,1000000],[4,5],[5,1000000]這樣的查詢區間,雖然可以保證左區間只掃一遍,但是右指標需要從頭到尾來回掃,時間複雜度一下子就上去了。莫隊演算法就是專門針對這種毒瘤題目的。
它的主要思想是分塊,對區間的範圍n開根號得到乙個d,每乙個查詢區間[l,r]的左區間l除以d,區間看作是全域性的第x塊,不同塊按的區間塊從小到大排序,同一塊的按右區間從小到大排序(不同塊看左,同塊看右)。
分塊排序寫乙個自定義比較函式就可以了。時間複雜度n*sqrt(n),具體證明看其他大佬部落格吧。
對於查詢的區間[l,r],指標移動操作比較常規,無非是左指標和右指標左右移動,[5,7]的答案可以由[5,8]或者[5,6]移動一次右指標解決,也可以由[4,7]或[6,7]移動一次左指標解決。對於區間查詢的貢獻,減去原來的,加上現在的。
入門題p2709
題意看了很久才懂,解釋一下資料,1到4出現了2個1,對答案貢獻2*2,出現1個2,對答案貢獻1*1,出現1個3,對答案貢獻1*1,加起來就是6。
#include#include#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 0x3f3f3f3f //
/填充無限小-0x7f
using
namespace
std;
struct
node
;node b[
50005
];int a[50005
];int num[50005
];int
n,m,k;
intd;
bool cmp1(node p1,node p2)///
分塊,對左區間開根號,左邊不在同一塊按左區間小到大排序,左邊在同一塊按右邊大小排序
bool cmp2(node p1,node p2)///
離線操作後恢復答案次序
int main()///
p2709 莫隊入門
sort(b+1,b+m+1
,cmp1);
int l=1,r=1
; num[ a[
1] ]=1
; ll ans=1
;
for(int i=1;i<=m;i++)
while(l///
左指標往右
while(r///
右指標往右
while(r>b[i].r)///
右指標往左
b[i].ans=ans;
}sort(b+1,b+m+1
,cmp2);
for(int i=1;i<=m;i++)
printf(
"%lld\n
",b[i].ans);
return0;
}
P2709 小B的詢問 莫隊演算法
題意 小b有乙個序列,包含n個1 k之間的整數。他一共有m個詢問,每個詢問給定乙個區間 l.r 求sigma c i 2 的值,其中i的值從1到k,其中c i 表示數字i在 l.r 中的重複次數。小b請你幫助他回答詢問。就是求區間不同數字個數的平方和 注意平方數可以拆開從1 n 遞推。include...
P2709 小B的詢問(莫隊演算法)
小b 有乙個長為 nn 的整數序列 aa,值域為 1,k 1,k 他一共有 mm 個詢問,每個詢問給定乙個區間 l,r l,r 求 sum limits k c i 2i 1 k ci2 其中 c ici 表示數字 ii 在 l,r l,r 中的出現次數。小b請你幫助他回答詢問。第一行三個整數 n,...
P2709 小B的詢問 莫隊
題目描述 小b有乙個序列,包含n個1 k之間的整數。他一共有m個詢問,每個詢問給定乙個區間 l.r 求sigma c i 2 的值,其中i的值從1到k,其中c i 表示數字i在 l.r 中的重複次數。小b請你幫助他回答詢問。輸入輸出格式 輸入格式 第一行,三個整數n m k。第二行,n個整數,表示小...