特別基礎的教程略。
\(cdq\)分治的優缺點:\(cdq\)分治與其他分治最本質的不同在於:( 1 )優點:**量少,常數極小,可以降低處理維數。
( 2 )缺點:必須離線處理。
分治到達\([l,r]\)時,分治處理\([l,mid]\)與\([mid+1,r]\)看起來這句話非常簡單,但只要正真理解了這句話,也就理解了\(cdq\)分治。然後遞迴上來合併的時候:
只考慮 [l,mid]中元素 對 [mid+1,r] 中元素的影響
只要是滿足這個原則的分治,都是可以稱作\(cdq\)分治的。
下面給出幾個例子,都是為了理解這句話:
給定長度為\(10^5\)的乙個序列,有一下兩種操作:樹狀陣列大水題.....(1)type=1:x val ,把序列第x位置的元素加上val
(2)type=2:x y , 求解[x,y]元素值的和
如果用\(cdq\)分治呢?(雖然非常非常沒有必要).
我們把求解\([x,y]\)元素之和拆分為求字首和\(pre[y]-pre[x-1]\)。
那麼會對\(pre[x]\)產生影響的為:操作時間在其之前,修改位置\(\leq x\)的修改操作。
建立二元組\((time , x)\),外部以time排序,然後分治。
分治時,每次以\(x\)歸併排序,
合併\([l,mid]\)與\([mid+1,r]\)時,統計\([l,mid]\)有幾個修改操作。
那麼如果在\([mid+1,r]\)碰到了修改操作,自然此時的統計數即為答案。
注意到上面:只統計[l,mid]的修改,只計算[mid+1,r]的答案。
這就是\(cdq\)分治的關鍵所在,因為這樣統計可以做到不重不漏,**見這裡。
三維偏序問題:三維偏序是\(cdq\)分治的最經典應用。給定\(n\)個元素,每個元素有三個屬性\(a,b,c\)。
定義\(f(i) = \sum_^n [i!=j]\times [a_j
試計算\(f(1),f(2),...f(n)\),資料範圍 \(n \leq 10^5\)。
先確定分治原則:
建立三元組\((a,b,c)\),外部先按照\(a\)排序,消除\(a\)的影響。
然後分治內部以\(b\)為準則進行歸併。此時我們保證了\(a_j與\(b_j
第三維\(c_j怎麼辦?用以\(c\)值建立權值樹狀陣列維護即可。
具體流程為:
(1)遞迴處理\([l,mid]\)與[mid+1,r];觀察到處理時,依舊滿足上面\(cdq\)分治的特性。(2)以\(b\)為準則歸併,其中:
( 2>1 )若為\([l,mid]\)元素,將其\(c\)值插入權值樹狀陣列
( 2>2 )若為\([mid+1,r]\)元素,在權值線段樹中查詢小於其\(c\)值的元素個數。
(3)回溯;
如果偏序原則中為\(\leq\)即可,那麼需要先去重。具體**見這裡
乙個非常大的誤區:\(cdq\)分治一定要歸併或邊歸併邊處理。
這其實是不對的,上面說過,只要滿足\(cdq\)分治原則就可以稱為\(cdq\)分治。
所以\(cdq\)分治的寫法其實是多重多樣,甚至不拘一格的。
\(cdq\)分治中的乙個難點就是確定分治原則。
在我們分治前,我們會確定元素的分治多元組。
分治多元組的確定關鍵是看分治中對答案的影響因素。
下面給兩個非常經典的例題:
序列初始為空,接下來每次會在指定位置\(i\)插入乙個元素\(x\)確定三元組\((time , pos , val)\),然後分治:求每次插入後,序列中的逆序對個數。
保證插入元素的值不重複,資料範圍\(n \leq 10^5\)
外部以\(time\)進行排序,消除\(time\)的影響。
然後內部以\(pos\)為原則進行歸併,然後怎麼處理呢?
考慮一下元素對答案的影響:
每次新增的點對此時答案的貢獻為:
(1)插入時間比它早,位置在它前面,值比它大的元素。
(2)插入時間比它早,位置在它後面,值比它大的元素。
所以我們先以\(pos\)從小到大歸併排序好。
然後從前往後正著掃一遍,
如果元素的\(time \leq mid\),那麼在樹狀陣列中插入它的\(val\)。
如果元素的\(time > mid\),那麼在樹狀陣列中查詢大於它的\(val\)的元素個數,加入答案。
然後再從後往前倒著掃一遍,處理方法一樣。
這樣我們最後就得到了每加入乙個元素新增的貢獻數,最後統計一下答案即可。
具體**戳我。
給定乙個大小為\(n*n\)的矩陣,初始每個格仔元素都為\(0\)貌似是上面的 例題1 的公升級版....一共有\(10^5\)個操作,操作如下:
(1)type=1:x y val ,把(x,y)位置的元素加上val。
(2)type=2:x1 y1 x2 y2, 查詢(x1,y1)到(x2,y2)這個矩形的元素和。
由二維變為三維,怎麼做呢? 其實差不多。
二維字首和之類的略,自己\(yy\),然後:
建立三元組\((time , x , y)\)
會影響詢問答案的為:操作時間早於其,x、y都小於等於它x、y的修改操作
所以外部以\(time\)排序,然後以\(x\)為原則歸併。
歸併的時候,如果是左邊區間的修改操作,把其修改值\(val\)值插入樹狀陣列中的\(y\)位置。
如果是右邊的查詢操作,查詢樹狀陣列中小於等於其\(y\)值的元素值之和。
這題做完了......
首先我們考慮三維偏序的解決方法:
外圍排序三元組變為\([l,b,c]與[r,b',c']\),然後歸併變為\([l,l,c]與[r,r,c']\)
所以此時只需要在樹狀陣列中查詢\(c\)了。
那麼四維是不是類似呢?
首先外圍排序,四元組變為\([l,b,c,d]與[r,b,c,d]\)
然後我們先以\(b\)為原則歸併,但是並不統計答案。
此時我們要記錄歸併好的序列中每乙個元素的\(a\)是屬於\(l\)還是\(r\)。
那麼此時只有\(b\)是有序的,\(a\)雖然無序但是我們記錄了其**(順序)。
即此時的四元組為\([l/r,l,c,d]\)與\([l/r,r,c',d']\)
此時把這個新的序列帶入下一層\(cdq\)中再跑一遍,不就是三維偏序的處理嗎?
但是這裡注意,為了保證\(a\)的順序,只有\([l,l,c,d]\)與\([r,r,c',d']\)的元素才是合法的。
這個也非常好解決,第一層\(cdq\)歸併時對每個元素打乙個標記即可。
具體的**見這裡
這裡提個醒,用巢狀\(cdq\)解決\(n\)維偏序問題的複雜度是\(o(n\ log^n)\)的。
其實搞懂了四維偏序的解決方法後,五維、六維....不是一樣的嗎?
四維時我們打了一層標記,消除了一維的影響,最終變為了三維偏序問題。
那麼\(n\)維我們則先歸併\(n-3\)遍,打\(n-3\)層標記。
這樣一共消除了\(n-3\)維的影響,然後再跑三維偏序即可。
實現五維偏序的具體**見這裡。
(1)luogu p3374 【模板】樹狀陣列 1(2)bzoj 3262陌上花開
(3)[shoi2007]tree 園丁的煩惱
(4)[cqoi2011]動態逆序對
(5)[hzoi 2016]偏序
(6)[hzoi 2015]改:偏序 ii
(7)[boi2007]摩基亞mokia
(8)bzoj 4237 稻草人
(9)[noi2007]貨幣兌換cash
CDQ分治總結
cdq這個東西嘛,說容易其實也很容易,說難其實也有些難,但只要細細品味,定能發現其中的真理的!那真理,也會像蝴蝶一般,破蛹而出,化身為一道亮麗的風景線。題記。咳咳,閒話就講到這裡了,切入正題。首先我們來了解一下cdq分治這個東東。cdq分治,他的常數小,但必須離線操作the most importa...
CDQ分治總結
目錄同步 經過了一周的划水,我終於搞懂了cdq分治。總的來說,cdq分治處理偏序問題就是 傳送門求靜態區域內的點數,二維偏序模板題。include includeconst int maxn 500000 5 5 x,y 橫縱座標 type 操作型別 add 求矩形區域面積用幾個矩形加加減減,所以a...
CDQ分治概述
log l og 的時間把它變成離線問題。正好有些題目的離線問題是比較簡單的。具體是什麼意思呢?我們對於每一層分治,只考慮前一半對於後一半的影響,然後在每個詢問當中記錄下來影響。最後把所有影響合併就可以得到每乙個詢問的答案。舉個例子 區間修改區間查詢。首先,在時間軸上離線分治。每一層分治後把詢問和查...