P2709 小B的詢問 普通莫隊 模板

2022-05-02 00:57:15 字數 1620 閱讀 2402

莫隊:莫濤隊長發明的演算法,尊稱莫隊。其實就是優化的暴力。

普通莫隊只茲磁詢問不支援修改,是離線的。

莫隊的基本思想:就是假定我得到了乙個詢問區間[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]中的重複次數

分析:

無修改莫隊模板題,用乙個陣列記錄當前區間每種數字出現的次數,在莫隊轉移是進行維護。

先讀入所有的查詢並排序,然後完成指標跳轉得到每次查詢的結果,最後根據查詢順序排序並輸出結果。

對查詢排序有兩種方法:

#includeusing

namespace

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的序列。接下...