【總結】伸展樹


伸展樹是一枚二叉樹,可以維護一個數列,或者可以作為二叉搜索樹,因為無論怎么旋轉,它的中序遍歷是不變的。

 

1、伸展操作。

Splay(x,goal):旋轉結點x,使它成為結點goal的兒子。

至於旋轉,本質上只有左旋和右旋。

 

2、插入。

如果作為二叉搜索樹,則插入與二叉搜索樹一樣,最后把該結點旋轉到根。

如果用於維護一個數列,要求在x位置之前插入val(val可以為一個數字或一個序列),則將第x-1個結點旋轉到根,將第x個結點旋轉到第x-1個結點的兒子,那么根據中序遍歷,val應插入在第x個結點的左兒子。

 

3、刪除。

與插入同理。

 

4、Select(k)。

在二叉搜索樹中,對每個結點維護一個num值,如果x左兒子的num+1=k,x就是第k小的數。

在維護序列中,顯然就是第k個數。

 

5、翻轉。

區間:將第a-1個數旋轉到根,將第b+1個數旋轉到a-1的兒子,那么b+1的左子樹就是區間[a,b]。

在b+1的左兒子標記翻轉,像線段樹一樣延遲標記,延遲標記往下推的時候交換左右兒子。

 

6、循環平移。

序列:1、2、3  --循環左移一位后->   2、3、1。

本質上就是兩個區間的交換。

 

坑爹的地方:

1、下標為0的結點作為邊界,它的pre、next值被亂搞沒關系,但是它維護的數值(比如 num,max,min...)不能影響到要維護的數列。

2、區間翻轉,則左右兒子交換,可能左右兒子維護的值也需要交換。

3、不斷的刪除和插入一段序列時,可能會爆內存,刪除的時候只好把刪除的結點壓到棧里,循環利用。

4、區間操作時,可以在序列的兩端加入兩個邊界結點1和n+2。避免討論,但它維護的數值不能影響到要維護的數列。

 

【HYSBZ】1588 營業額統計

數據有問題,用Splay實現很裸的二叉搜索樹。

 

【POJ】3481 Double Queue

依然是Splay實現二叉搜索樹。

 

【HYSBZ】1503 郁悶的出納員

依然是Splay的操作。如果在平衡樹中維護一段區間,蛋就碎了。

I命令:立刻離開不算入離開公司的員工的總數。

可以把數據分成兩部分,在Splay中的部分,和待加入平衡樹的部分。

把Splay中的數據同時加上val(val可能為負),相當於把待加入Splay的部分同時減去val,因為兩個部分數據的相對值不變。

S命令:刪除Splay中小於相對標准的子樹。

 

【HDU】1754 I Hate It

Splay維護區間最值。

線段樹是一個區間平分為兩個子區間。

Splay根據中序遍歷,把一個區間分為左、中、右。

維護上大同小異。

 

【HDU】3487 Play with Chain

刪除、插入、翻轉,之前扯淡過了。

 

【HYSBZ】1500 維修數列

修改、求和、最大連續子序列和、都和線段樹一樣,翻轉的時候左右連續的最大和要交換。

 

【POJ】3580 SuperMemo

循環移動T次,T>0表示左移,T<0表示右移。取模以后都轉換成左移即可。

 

【HDU】2475 Box

很容易想到,5在1內可以把5作為1的兒子,那么可以得到一片森林,而且兒子可能很多。

那么可以用動態樹,其實用Splay也可以做到。

那么建樹完DFS一遍,可以得到一個或者多個括號序列。比如2在1內,3在1內,4在3內就是1 2 2 3 4 4 3 1。

接下來,可以用Splay維護多個序列。

詢問root的時候,就是該序列的最左端的值。

移動的時候,就是把一段序列移到另一段序列中。

 

【HDU】3726 Graph and Queries

給出一個無向圖,圖中每個頂點都有一個權值:

1、刪除一條邊;

2、詢問與頂點x連通的頂點中,第k大的值。

3、改變某個頂點的權值。

輸出所有詢問的平均值。

膜拜ghnjk大神的做法和他的AVL……

由於刪一條邊不能確定該圖是否邊分成兩個連通分量,但是加入一條邊可以判斷是否把兩個連通分量連通、或者還是一個連通分量(並查集)。

所以離線讀入所有詢問,把每個頂點的權值存入該頂點的鄰接表。

初始時,每個頂點都是一個單獨的Splay。

當合並兩個集合時,將兩枚Splay合並,由於兩枚Splay的值不會總是嚴格大於對方,所以只好把小的Splay的每個頂點插入到大的Splay中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM