1. 程式人生 > >CDQ分治與整體二分

CDQ分治與整體二分

結構 十分 read 代碼 遞歸 都是 好的 重新 ora

前言


本來想要只講CDQ分治的,但由於整體二分和CDQ分治有一些相似之處,便順藤摸瓜一起講了

在講解之前,先普及一下在線算法和離線算法的定義

在線算法: 可以以序列化的方式一個一個的處理輸入,不必事先知道所有輸入數據

離線算法: 必須事先知道所有的輸入數據 (例如選擇排序就是一個離線算法,而插入排序則不是)

還有一點,在學習算法前掌握凸殼和斜率優化可能會有神助

CDQ分治


CDQ分治,是一種十分優美的暴力算法。它可以代替很多比較玄學的數據結構,乃廣大OIer的福音

但是,不得不感嘆一句,網絡上關於CDQ分治的講解實在是太少,而且語言過於抽象,

這導致很多OIer沒能接觸到其魅力就避而遠之。

CDQ分治的關鍵在於,每個子問題不僅是解決它自身,並且用前一個子問題來求解後一個子問題。常用來將一些動態的問題轉化到靜態來解決,使問題處理起來更加方便。
使用CDQ分治需要滿足一定的條件:

1.題目允許離線操作

2.修改操作對詢問的貢獻獨立,且修改之間互不影響

3.修改對答案的貢獻是確定的,與判定標準無關

4.常數小

揭開這個幌子,先來舉例說明這個算法的特點

1.代碼簡短(比起樹套樹來說)

2.易想出

3.為離線算法(化動態開點為靜態查詢),如果需要強制在線的話還是推薦其它算法

和普通的分治一樣,分和治在這個算法中都得到了很好的展現

1.我們要解決一系列問題,這些問題一般包含修改和查詢操作,可以把這些問題排成一個序列,用一個區間[L,R]表示。

2.分。遞歸處理左邊區間[L,M]和右邊區間[M+1,R]的問題。

3.治。合並兩個子問題,同時考慮到[L,M]內的修改對[M+1,R]內的查詢產生的影響。即,用左邊的子問題幫助解決右邊的子問題。

和很多數據結構(線段樹,樹狀數組。。。)一樣,它做了這麽多是為了什麽?就是為了把符合本次查詢的限制的修改對答案產生的效果合並起來

整體二分


說完了CDQ分治再來說說整體二分

相對於CDQ分治,整體二分的知名度會更高一些,是很多OIer在解決一些問題時的常用方法

整體二分產生的原因:對於單個查詢而言,我們可以采用預處理+二分答案的方法解決,但往往我們要回答的是一系列的查詢,對於每個查詢而言我們都要重新預處理然後二分,時間復雜度無法承受,但是我們仍然希望通過二分答案的思想來解決,整體二分就是基於這樣一種想法——我們將所有操作(包括修改和查詢)一起二分,進行分治

簡單地說,整體二分就是對詢問和答案同時二分

同樣的,整體二分也需要滿足一定的條件:

1. 題目允許離線操作

2. 修改操作對詢問的貢獻獨立,且修改之間互不影響

3. 修改對答案的貢獻是確定的,與判定標準無關

4. 答案具有二分性

5.貢獻滿足交換律,結合律,具有可加性

CDQ分治和整體二分的異同


同:

1.都是按時間進行分治

2.代碼很像(不完全一樣,這在異中會講到)

3.復雜度都是O(f(n)logn)

異:

1.整體二分有二分答案操作

2.適用範圍不同(具體看上面的使用條件)

CDQ分治與整體二分