莫隊:莫濤隊長發明的演算法,尊稱莫隊。其實就是優化的暴力。
普通莫隊只茲磁詢問不支援修改,是離線的。
莫隊的基本思想:就是假定我得到了乙個詢問區間[l,r]的答案,那麼我可以在極短(通常是o(1))的時間複雜度內得到[l+1,r]的答案——於是對於區間查詢類的題目,我可以一次性讀完所有詢問之後來回轉移,得到每乙個區間的答案。
如果可以通過區間[l,r]快速轉移到[l-1,r][l+1,r][l,r-1][l,r+1],那麼可以用o(x*|l1-l2|+|r1-r2|)的時間完成轉移,[l2,r2]是[l1,r1]的後一次詢問,x是[l,r]轉到相鄰區間的複雜度,我們讓這個值最小,就是求曼哈頓距離最小生成樹,但是這個比較難求。可以用分塊加上一定規則來排序,以左端點所在塊的編號為第一關鍵字排序,右端點的值作為第二關鍵字排序,最壞複雜度和上面的曼哈頓距離最小生成樹是一樣的,這個樣子做的複雜度是 $o(n \sqrt n) $(不會證,反正使用分塊後複雜度就是這)。
在這裡,分塊的作用就是加速而已。
小b有乙個序列,包含n個1~k之間的整數。他一共有m個詢問,每個詢問給定乙個區間[l..r],求sigma(c(i)^2)的值,其中i的值從1到k,其中c(i)表示數字i在[l..r]中的重複次數
分析:
無修改莫隊模板題,用乙個陣列記錄當前區間每種數字出現的次數,在莫隊轉移是進行維護。
先讀入所有的查詢並排序,然後完成指標跳轉得到每次查詢的結果,最後根據查詢順序排序並輸出結果。
對查詢排序有兩種方法:
#includeusingnamespace
std;
typedef
long
long
ll;const
int maxn = 50000 + 10
;struct
queq[maxn];
intn, m, k;
ll block[maxn], num[maxn], sum[maxn], size;
ll ans;
//block: 分塊陣列 size分塊大小
//sum[i]: 元素i的個數
void
init()
//莫隊精髓一
bool
cmp(que x, que y)
bool cmpp(que x, que y)//
第二種排序方式,快一些
//按查詢順序排序,用於輸出答案
bool
cmp_id(que x, que y)
//莫隊精髓二:轉移
void modify(int x, int
w)void
solve()
}int
main()
init();
sort(q+1, q+m+1, cmp); //
or cmpp
solve();
sort(q+1, q+m+1
, cmp_id);
for(int i = 1;i <= m;i++)
printf(
"%lld\n
", q[i].res);
return0;
}
1. 2.
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個整數,表示小...
P2709 小B的詢問 莫隊
題面只要能想出 o 1 的方式轉移 l,r 莫隊就不難了。此題求區間 sum kcnt i 2 那我們就 o 1 更新就好了,先減去原來的貢獻,更新cnt再加上現在的貢獻,這樣就更新完了。注意 莫隊小心初始化,直接l 0,r 0等可能會炸。include include include define...
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個整數,表示小b的序列。接下...