學習筆記--cdq
阿新 • • 發佈:2021-08-28
學習筆記-cdq
暑假學了cdq,搞得不是特別明白,寫一篇部落格梳理一下。
cdq演算法是什麼?
最開始我對它的理解是歸併排序,這個理解終究是狹隘了。歸併排序只是cdq演算法的一小部分,連冰山一角都說不上。
CDQ演算法指的是:
\(1.\)對於一個問題:劃分左右區間 \([l, mid]\)和\([mid + 1, r]\)
\(2.\)分別解決左區間和右區間的子問題
\(3.\)計算左區間對右區間的影響
\(4.\)合併左右區間得到原問題的解。
看起來很簡單的樣子,正因為如此,cdq的應用範圍十分的廣泛,從歸併排序開始,到優化dp再到各種模型,你可以在很多地方看到cdq的身影
光說不練假把式,瞭解了定義並不代表掌握了這個演算法,需要做相關的練習。
那麼就從一些題目入手,來鞏固學習cdq分治,掌握其核心思想
T1 LuoguP1908逆序對
對於給定的一段正整數序列,逆序對就是序列中 \(a_i>a_j\) 且 \(i<j\) 的有序對。
暴力無疑是很好想的那麼我們如何入手優化呢
首先,我們假設自己沒有立刻想到cdq演算法,而是從最原始的開始一步步推導,
我們要找到 \(a_i>a_j\) 且 \(i<j\) ,那麼是不是對於一個a_i,不重複的話只有後面的可以影響到它的答案統計
再看暴力是如何運作的,
for(register int i=1;i<=n;++i) a[i].x=read(),a[i].id=i; sort(a+1,a+n+1);
然後再根據位置關係進行統計,既然如此,考慮排序方式,有什麼辦法可以快速統計後面的會產生貢獻的元素呢?
這個時候我們就會想到歸併演算法。 \(\rightarrow cdq\) 演算法就此登場!
繞了一大圈子,主要是想講明思維的推導過程,這種思維方式同樣也可以運用到之後的學習
T2 [Violet 3]天使玩偶
這道題先考慮回憶出來的點都在詢問的點左下方時:則當\(x_B + y_B\)取到最大值時,\(Dis(A,B)\) 有最小值。實際上就是三維偏序
至於三維偏序:利用樹狀陣列和歸併進行操作
\(cdq\)分治每次計算前一半對後一半的影響。
具體地,
假設三維分別是 \(x,y,z,\)
先按\(x\)排序。分治時每次將前半邊、後半邊分別按\(y\)排序。
雖然現在\(x\)的順序被打亂了,但是前半邊還是都小於後半邊的,所以要是隻計算前半邊對後半邊的偏序關係,是不會受到\(x\)的影響的。
維護後一半的指標\(p\),前一半的指標\(q\),每次將\(p\)後移一位時,若\(y[q]<=y[p]\)則不斷後移\(q\),並不斷將\(z[q]\)加入樹狀陣列。然後再查詢樹狀陣列中有多少數小於等於\(z[p]\)。
最後要清空樹狀陣列。