1. 程式人生 > >樹套樹亂講

樹套樹亂講

有序 block 插入 題目 每一個 定義 是把 線段樹 輸出

樹套樹亂講

樹狀數組套線段樹

先學會主席樹。

主席樹可以被理解為一個二維平面,其中n棵樹可以視作橫軸,每棵樹中的坐標範圍(也就是線段樹的坐標範圍)可以視作縱軸。這樣一來就是用主席樹維護了一些在二維平面上的點,給定\(a,b,c,d\),可以在\(O(\log{n})\)的時間內求出滿足\(a\le x_i\le b,c\le y_i\le d\)\(i\)的數量。

而樹狀數組套線段樹就是把這個問題動態化。

對於上述的問題,我們是通過對主席樹直接維護前綴和,查詢時兩棵主席樹相減,再在區間\([c,d]\)上查詢答案的。既然已經維護了前綴和,那麽一個單點修改就會涉及到\(n\)棵主席樹從而使修改的時間復雜度炸裂。

那麽現在我們就考慮用更為靈活的樹狀數組來維護前綴和。

把主席樹的前綴和用樹狀數組的形式表示,每次單點修改時在\(\log{n}\)棵線段樹上修改,查詢時也是在\(\log{n}\)棵線段樹上查。

時間復雜度\(O(n\log^2{n})\)

動態區間Kth

支持數組的單點修改,區間查Kth

單點修改就是樹狀數組的單點修改。

用樹狀數組維護前綴和,這時一個區間可以用\(\log{n}\)棵線段樹與\(\log{n}\)棵線段樹作差的形式來表示。

在線段樹上二分,復雜度\(O(n\log^2{n})\) 代碼1.9k

三位偏序(陌上花開)

第一維排序第二維樹狀數組第三維權值線段樹
做完了,代碼1.5k

【模板】二逼平衡樹

您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:

1、查詢k在區間內的排名
2、查詢區間內排名為k的值
3、修改某一位值上的數值
4、查詢k在區間內的前驅(前驅定義為嚴格小於x,且最大的數,若不存在輸出-2147483647)
5、查詢k在區間內的後繼(後繼定義為嚴格大於x,且最小的數,若不存在輸出2147483647)

樹狀數組套線段樹。
1、查k的排名就是查區間內\([1,k-1]\)的數的個數+1
2、排名為k的值,見動態區間Kth
3、樹狀數組修改
4、相當於操作二查排名為“\([1,k-1]\)內數的個數”的值
5、相當於操作二查排名為“\([1,k]\)

內數的個數+1”的值

時間復雜度\(O(n\log^2{n})\),代碼3.2k

[ZJOI2013]K大數查詢

你有n個位置,每個位置初始是空的。
一種操作是在a位置到b位置上每個位置插入一個元素c
一種操作是查詢a位置到b位置上第k大的數

報告!我會整體二分!不好意思,強制在線
首要考慮的是內外層的關系:位置和權值哪個作為內層,哪個作為外層?

方案一:外層位置內層權值。
發現操作一是一個區間修改,操作二是一個區間查詢。不知道能不能寫。

方案二:外層權值內層位置。
發現操作一是一個單點修改,操作二是一個線段樹上二分。
所以就線段樹套線段樹,即線段樹上的每一個點都是一棵線段樹的根。

時間復雜度\(O(n\log^2{n})\),代碼1.5k

[HNOI2016]網絡

給你一棵樹,支持如下三種操作:

1、在樹上插入一條兩端點為\(u,v\),權值為\(w\)的鏈。
2、刪除之前插入的某一條鏈。
3、查詢未經過點\(x\)的鏈中的權值最大值

可在線。

首先把鏈剖成\(\log{n}\)個區間(dfs序上的區間)。
把區間反轉,在不在這\(\log{n}\)個區間範圍內的區域做覆蓋。
這樣就可以查詢覆蓋了\(x\)點的鏈中的最大值就可以了。

由於有刪除操作所以線段樹上的每個節點開一個刪除堆。
時間復雜度\(O(n\log^3{n})\) 代碼3.2k

後記

樹狀數組套平衡樹我沒寫過,yyb說用來寫三維偏序然而三位偏序不是被我樹狀數組套線段樹水過去了嗎
總之,大家根據自己的代碼風格以及對這些數據結構的熟練程度進行取舍吧
還有對於那些沒有強制在線的題目,采用cdq分治或者是整體二分都是不錯的選擇。

樹套樹亂講