【題目描述】
您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
插入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 行,每行乙個...