2020ZROI寒假集訓Day2 分治與分塊 總結

(只講新學會的)

1、點分治解決合法括號序列路徑計數

首先每一個括號序列可以把它縮成一堆)))和一堆(((

記錄一下當前點分治中心到子樹中任意節點的簡化括號序列的剩餘左右括號數目(要記錄兩種一種是從上向下、另一種是從下向上),然後在點分治中心合併答案即可

至於怎麼記錄從下向上的簡化括號序列,可以考慮從序列左邊插入括號來維護棧

 

2、點分樹

一棵樹,n個點,有點權,多次詢問,求到點x距離小於等於k的節點的點權和

先考慮點分治的過程,把每次的分治中心按層排列爲樹形結構

那麼點x爲分治中心時所管轄的點的合法點權和可以通過nlogn預處理出來(直接用一個數組做前綴和)

然後找到x點在點分樹上的父親,向上跳,查詢,減掉來自x子樹的貢獻(點分治經典去重)

因爲點分樹的深度是logn的,所以一次查詢是logn的

如果可以修改點權?

把每一個點分治中心維護的前綴和數組改爲樹狀數組即可,一次查詢需要(logn)^2

 

3、邊分樹

(1)、三度化

就是加入0權邊和虛點,把菊花圖優化一下,這樣邊分治就不會被菊花圖卡了

(2)、邊分樹

其實解決問題的方法和邊分樹差不多,只不過它有一個優點就是,它是二叉樹,方便合併

但是也有缺點,如果問題無法三度化(或三度化之後會影響準確性),就不能用邊分治

 

 

4、[ZJOI2007]捉迷藏

計算最遠黑點點對的距離,帶修改顏色,有邊權

題解:建出邊分樹

對每個邊分治中心開一個multiset,維護該邊分樹子樹節點到當前邊距離的集合

然後兩邊找最大的合併即可(就像線段樹)

如果要修改顏色,就需要改logn個multiset的值才能再一次維護處全局的答案,所以是(logn)^2

也有不用multiset的做法

就是每一個邊分治中心存一下它管轄範圍的直徑端點,然後每次向上合併的時候都需要用6次LCA(如果把之前的直徑長度存下來就是4次)

 

5、[ZJOI2015] 幻想鄉戰略遊戲(佔坑,後面還有很多內容)

 

6、一道CF的題

一棵樹,點邊均帶權,找一個點x使\sum_{i!=x}a_i*dis(i,x)^{1.5}最小(a爲點權)

做法:建出點分樹

然後從整棵樹的分治中心向下走,每次找答案最小的兒子走(有點貪心,因爲x^1.5是凸函數,所以就可以通過比較導數來確定最優解的位置,有點爬山的思想)

 

7、環形郵局問題

法一:隨機破環爲鏈

法二:由於四邊形不等式的本質就是交錯更優,所以我們可以隨便選一個點作爲起點

用wqs二分求出它的決策點集合,然後找到最近的兩個決策點,在他們之間來進行枚舉

時間複雜度O(n^2/k*logn*logn)或O(n^2logn)

法三:利用最優路徑和當前路徑不交叉的性質,分治套分治,O(n*logn*logn)

 

8、分塊,塊內維護所有值的有序序列解決區間小於等於k的數的個數

區間查詢:兩邊暴力,中間在每個塊內二分

區間加修改:中間的打標記,兩邊下放標記,塊中把修改的數與沒修改的數用歸併排序重構

總複雜度O(m*sqrt(nlogn))

塊大小sqrt(nlogn)

(注意這裏的loglogn是被忽略了的)

 

9、分塊解決區間第k大,區間加(Ynoi2017舌尖上的由乃)

區間查詢:對每個塊進行二分,邊緣的兩個塊歸併起來二分

區間修改:同8

塊大小sqrt(n)*logn

時間複雜度O(m*sqrt(n)*logn)

 

 

10、根號平衡(爲莫隊做鋪墊)

值域分塊(注意這裏的第k小時全局的第k小)

先把所有的值離散化一下

每一個塊維護一個已經存在點數,顯然,這樣可以做到O(1)維護

然後查詢就直接從1號塊的點數一次累加,當超過k時,就說明答案在當前塊中,在掃一下當前塊內部就可以了

相當於寫了一個O(1)insert,O(sqrt(n))query的set

 

塊狀鏈表(思路差不多)

還是對值域分塊

插入的時候暴力找到插入的位置,然後塊內直接插入,這時這個塊可能會擠出來一個元素(我們要把每個塊大小爲sqrt(n),除尾端塊),於是我們就把這個元素放到下一個塊中,然後可能就會擠出來一個元素……擠出來的元素只會是塊尾,最多可能擠出來sqrt(n)次,所以複雜度是sqrt(n)的

怎麼查詢?

直接數學方法定位即可(因爲前面的每個塊的大小都是sqrt(n)了)

 

 

11、一道codechef的題

題解:

思路非常巧妙

對函數編號分塊,每個塊統計一下它當前的函數值總和

這樣查詢應該都會了

怎麼修改?

每個塊維護一個差分數組,把塊內函數的左端點++,(右端點+1)--,單點修改的時候就需要看當前點對每個塊答案的貢獻

這個貢獻就是它在一個塊中,分別被多少個函數覆蓋,直接查當前位置x的前綴和就可以了

總時間複雜度:O(m*sqrt(n))

 

 

12、莫隊如何卡常數

 

 

對了,莫隊的複雜度是O(n*sqrt(m))的,不是O(m*sqrt(n))

 

 

13、[Ahoi2013]作業

一看就可以直接用莫隊+樹狀數組

但是會TLE

因爲莫隊等價於n*sqrt(m)次修改操作與m次查詢操作

如果能將修改操作的時間複雜度降下來就好了

聯想到之前的值域分塊,稍加思索,就有了一個O(1)insert,O(sqrt(n))query的set了

複雜度就降爲了

O(m*sqrt(n)+n*sqrt(m))

感覺還是會TLE啊。。。

 

 

14、 [Ynoi2016]這是我自己的發明

(先佔一個坑,主要是不會換根操作。。。)

 

 

15、[Ynoi2015]此時此刻的光輝

n<=10^5    mod=19260817   。。。

 

題解:

約數個數是可以通過每個質因子的個數來計算的

所以我們先把所有的數分解質因數

然後把所有的質因數離散化

就可以莫隊啦

然而這樣會TLE

因爲一次修改可能會帶來logn次操作

怎麼辦呢?

我們可以按質數大小來分類討論

我們把1~1000的168個質數預處理出它對答案貢獻的前綴和

然後我們加的較大的質數就不會超過三次

這樣修改的複雜度就降爲O(1)左右了

查詢的複雜度就是O(168)約等於O(sqrt(n))

所以總複雜度爲O(n*sqrt(m)+m*sqrt(n))

 

 

 

 

(差不多了,其他的都沒怎麼聽懂。。。)