1. 程式人生 > >樹套樹

樹套樹

基礎 線段樹 它的 更新 成了 得到 clas 都是 保存

  樹套樹,顧名思義,就是用一顆樹套在另外一組樹之上。比方說我們有一顆樹,假如它的每一個結點(抽象意義上,一株樹由多個結點組成)也是一株樹,那麽這就形成了樹套樹。外部樹和內部樹可以是不同品種的。一般外部樹都是形如線段樹或樹狀數組等用於統計和區間處理但是內存消耗大的樹,而內部樹則往往是像Splay一樣功能強大且內存消耗小的樹,當然這不是絕對的。

  考慮這樣的一個場景,給你一組數值序列S={v1,v2,....},要求你快速求區間[L,R]之間第k小的值,並且數值序列中可能有若幹元素會被修改。如何解決?首先我們建立一株線段樹,線段樹內每個區間(對應原線段樹結點)均用Splay樹維護,區間[x,y]對應的Splay樹用於保存子序列S[x...y]中的值。顯然一次更新操作,我們只需要更新log2(n)個區間,對應的也就是log2(n)個區間,更新操作可以用刪除原Splay結點並插入一個新的結點來實現,因此一次操作的空間復雜度為O(log2(n)),當然時間復雜度為O(log2(n)*log2(n))。而一次詢問操作,我們只需要對可能的值做二分查找,因此問題就轉化成了詢問S[L...R]中小於某個特定值v的值數目。而具體的實現是,對於線段樹我們僅查找區間[L,R]下對應的多棵Splay樹,統計每一株樹中小於v的結點數目,就可以得到正確結果。因此詢問操作時間復雜度為O(log2(|V|))*log2(n)*log2(n))。其中V表示值域,由於值域較難控制,我們也可以選擇用線段樹維護值信息,而用Splay維護區間統計信息,這樣時間復雜度就為O((log2(n))^3),但是這一般需要提前對數據(包括初始數據和後面修改的所有數據)進行預先離散化處理,相應的消耗的空間也會更大。

  也許你會問,為什麽要用Splay樹作為內部樹,Splay樹在上面場景中不就是用於統計區間信息嗎,為什麽不直接使用線段樹套線段樹呢。這是因為在創建外部樹時,我們就會創建內部結點,而如果內部結點是空Splay樹,每個結點消耗的空間都是常數,如果是線段樹,那麽消耗的空間就是O(n),這樣由於外部樹有O(n)個內部樹結點,而每棵內部樹的空間復雜度都是O(n),那麽空間復雜度將達到O(n^2)。當然你可以選擇先建立一株空樹,之後多株線段樹在空樹的基礎上進行可持久化修改,這樣初始化的空間復雜度與線段樹套Splay樹一致,但是每次後續修改操作其花費的空間復雜度為O(log2(n)*log2(n)),比線段樹套Splay樹的O(log2(n))要大。

  樹套樹的玩法應該還有很多,以後遇到了再補上。

樹套樹