資料結構 Splay伸展樹 普通平衡樹

2021-09-13 12:09:34 字數 3487 閱讀 7491

【題目描述】

您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

插入x數

刪除x數(若有多個相同的數,因只刪除乙個)

查詢x數的排名(若有多個相同的數,因輸出最小的排名)

查詢排名為x的數

求x的前驅(前驅定義為小於x,且最大的數)

求x的後繼(後繼定義為大於x,且最小的數)

【輸入】

第一行為n,表示操作的個數,下面n行每行有兩個數opt和x,opt表示操作的序號(1<=opt<=6)

【輸出】

對於操作3,4,5,6每行輸出乙個數,表示對應答案

【樣例輸入】

81 10

1 20

1 30

3 20

4 22 10

5 25

6 -1

【樣例輸出】220

2020

【提示】

n<=100000 所有數字均在-107到107內

【思路】

splay是基於二叉查詢樹的一種改進。它的基本思想就是每次操作以後,通過多次旋轉與當前操作有關的乙個節點到根節點以改變樹的形態,以達到樹的形態趨於隨機的目的(說白了就是瞎搞)。它的加入等操作與二叉查詢樹差不多,不同的是它有splay(伸展)的操作。伸展操作是基於雙旋,先旋轉父節點再旋**己,可以達到改變樹的形態的目的,不能雙旋時再進行單旋。刪除操作一般是先把要刪除的節點旋轉到根節點,再合併左右子樹,一般用左子樹的最大權值的節點充當新根以達到刪除的目的。關於伸展操作,一般分三種情況處理:

情況一:節點x的父節點y是根節點。這時,如果x是y的左孩子,我們進行一次zig(右旋)操作;如果x是y的右孩子,則我們進行一次zag(左旋)操作。經過旋轉,x成為二叉查詢樹s的根節點,調整結束。

情況二:節點x的父節點y不是根節點,y的父節點為z,且x與y同時是各自父節點的左孩子或者同時是各自父節點的右孩子。這時,我們進行一次zig-zig操作或者zag-zag操作。

情況三:節點x的父節點y不是根節點,y的父節點為z,x與y中乙個是其父節點的左孩子而另乙個是其父節點的右孩子。這時,我們進行一次zig-zag操作或者zag-zig操作。

其它的一些操作:

(1) find(x,s):判斷元素x是否在伸展樹s表示的有序集中。首先,訪問根節點,如果x比根節點權值小則訪問左兒子;如果x比根節點權值大則訪問右兒子;如果權值相等,則說明x在樹中;如果訪問到空節點,則x不在樹中。如果x在樹中,則再執行splay(x,s)調整伸展樹。

(2) insert(x,s):將元素x插入伸展樹s表示的有序集中。首先,訪問根節點,如果x比根節點權值小則訪問左兒子;如果x比根節點權值大則訪問右兒子;如果訪問到空節點t,則把x插入該節點,然後執行splay(t,s)。

(3) join(s1,s2):將兩個伸展樹s1與s2合併成為乙個伸展樹。其中s1的所有元素都小於s2的所有元素。首先,我們找到伸展樹s1中最大的乙個元素x,再通過splay(x,s1)將x調整到伸展樹s1的根。然後再將s2作為x節點的右子樹。這樣,就得到了新的伸展樹s。

(4) delete(x,s):把節點x從伸展樹表示的有序集中刪除。首先,執行splay(x,s)將x旋轉至根節點。然後取出x的左子樹s1和右子樹s2,執行join(s1,s2)把兩棵子樹合併成s。

(5) split(x,s):以x為界,將伸展樹s分離為兩棵伸展樹s1和s2,其中s1中所有元素都小於x,s2中的所有元素都大於x。首先執行find(x,s),將元素x調整為伸展樹的根節點,則x的左子樹就是s1,而右子樹為s2。

**:

#include

#include

#include

#include

#include

#include

#include

#define re register

#define ll long long

using

namespace std;

int n,a,b,c,root;

int ch[

1000001][

2];int fa[

1000001];

int val[

1000001];

int siz[

1000001];

int m[

1000001];

int tot=0;

inline

intget

(int x)

inline

void

pushup

(int p)

inline

void

rotate

(int x)

inline

void

splay

(int u,

int tar)

rotate

(u);}if

(!tar) root=u;

}inline

void

insert

(int w)

if(w)dir=

0,u=ch[u][0

];else dir=

1,u=ch[u][1

];}if

(root==

0)root=u;

u=++tot;

val[u]

=w; siz[u]

=m[u]=1

; fa[u]

=v;if

(v)ch[v]

[dir]

=u;splay

(u,0);

}inline

intfindmx

(int u)

inline

void

join

(int u,

int v)

inline

intfind

(int x)

return0;

}inline

void

delete

(int u)

if(siz[u]==1

)root=0;

elseif(

!ch[u][0

]||!ch[u][1

])else

}inline

intfind_x

(int x)

if(u)

splay

(u,0);

return res;

}inline

intfind_k

(int k)

if(u)

splay

(u,0);

return0;

}inline

intfind_over

(int x)

return res;

}inline

intfind_pre

(int x)

return res;

}void

print

(int u)

intmain()

}

高階資料結構 伸展樹(Splay Tree)

伸展樹 splay tree 是一種二叉搜尋樹,它能在o log n 內完成插入 查詢和刪除操作。它由daniel sleator和robert tarjan創造。它的優勢在於不需要記錄用於平衡樹的冗餘資訊。在伸展樹上的一般操作都基於伸展操作。各種二叉搜尋樹存在不足。比如 對於乙個有n個節點的平衡二...

splay 文藝平衡樹 資料結構

題目大意 略 splay維護區間翻轉裸題,為了減少不必要的麻煩,多插入兩個點,分別是0和n 1 每次找區間的第k個值,就在splay上二分即可 順便學了一下splay的完美建樹,而且splay有一些小函式可以巨集定義或者用inline,跑得飛快 最後跑一遍中序遍歷即可 1 include 2 inc...

資料結構 day 4 splay 平衡樹初步

抓夢腳的一天。給你乙個長為n 的序列 a1 a2 an 你需完成q 個操作,操作分兩種 modify l r d 表示將l 到r 這個區間的數加上d query p 表示詢問p 這個位置的值 input 第一行乙個整數n。第二行n 個整數表示a1 a2 an。第三行乙個整數q。接下來q 行,每行乙個...