一般的分治,眾所周知的,是通過將大的問題拆小,然後對小問題的答案進行合併得到大問題的答案,但是cdq分治不是。我們知道,分治時,將乙個區間從中間斬開,分兩半處理,cdq分治在處理完之後,不是合併答案,而是計算左區間對右區間的貢獻,這樣子可以將維度降低,問題就更好做了。
現在有 n大佬瞟一眼就能發現,這就是逆序對問題嘛。nn 個二元組,每個形如 (a,
b)
(a,b)
(a,b
),現在問有多少對二元組之間是吊打的關係。ps:x
xx 吊打 y
yy 的定義是
x的a>y的a , x的b>y的b
。
我們對關鍵字 a
aa 進行排序,這樣我們就可以忽略 a
aa 的影響了,後面用權值樹狀陣列即可求解。
可見,排序是一種強大的降維**!
問題公升級!
現在有 n我們發現,用排序進行降維之後,還剩下兩維呀!而排序這個**是顯然只能用一次的,那對於二元組顯然也難以求解,於是,我們還需要降維,用誰呢?nn 個三元組,每個形如 (a,
b,c)
(a,b,c)
(a,b,c
),現在問有多少對三元組之間是吊打的關係。ps: x
xx 吊打 y
yy 的定義是
x的a>y的a , x的b>y的b , x的c>y的c
。
神奇的cdq分治登場!
依照上面的思想,我們可以對關鍵字 b
bb 進行分治,每次將序列分成兩半,將這兩半分別按照關鍵字 b
bb 排序,那麼現在我們知道,左邊部分的 a
aa 都小於右邊部分的 a
aa(假設我們從小到大排序),那麼我們只需要將左邊部分中 b
bb 也小於右邊部分 b
bb 的那些加入權值樹狀陣列,然後統計答案即可。
(這麼說我自己都覺得抽象。。) 那麼來看看**吧!
void
solve
(int x,
int y)
for(
int i=x;i)//清空樹狀陣列
add(a[i]
.z,-a[i]
.w);
}
當然,cdq分治的強大之處還不止這樣,它不僅和排序一樣可以降一維,它還比排序要厲害一些——它可以巢狀!
這樣,就可以降更多維了,而時間複雜度僅僅是隨著巢狀層數增加若干個log而已!而且,空間上完全無負擔。
具體做法可能以後會補上吧qwq,這裡先坑一下了
CDQ分治小結
一道cdq分治的比較模板又不是模板的問題.設 f i 表示 a j a i 且 b j b i 且 c j c i 的 j 的數量 對於 d in 0,n 讓你求 f i d 的數量 其實個人感覺模板的話 還是嚴格小於比較好做 先來考慮一下嚴格小於該怎麼做 我們先對整體按照 a i 排序,這樣的話我...
cdq分治學習小結
一臉懵逼的學了好久,應該算學會了吧。基本了解cdq分治的思想,然而 一如既往的醜。cdq分治只支援離線操作,主要作用是降維,反正就是大大優化了時間和空間。感覺不扯幾句作用非常不好 輸入長度為n的序列,並進行m次操作,操作分兩種 1.將編號為的數加上y 1 x y 2.求出某區間每乙個數的和 2 x ...
CDQ分治概述
log l og 的時間把它變成離線問題。正好有些題目的離線問題是比較簡單的。具體是什麼意思呢?我們對於每一層分治,只考慮前一半對於後一半的影響,然後在每個詢問當中記錄下來影響。最後把所有影響合併就可以得到每乙個詢問的答案。舉個例子 區間修改區間查詢。首先,在時間軸上離線分治。每一層分治後把詢問和查...