最近系統的學習了學習平衡樹(splay),現做如下總結。
簡而言之,平衡樹是一種二叉樹。
何為平衡呢?平衡樹的「平衡」是由於他的深度較為平衡,一般穩定在log級別。
平衡樹因其「平衡」而保證了時間複雜度,減少了被卡的概率。
我們如何操作呢?
利用乙個性質:平衡樹因為中序遍歷是有序的,所以他的左子樹的所有元素都比他小,右子樹都比他大。
設旋轉的點為x,他的父親為y,父親的父親為z,son(a)表示a是他父親的左兒子還是右兒子。
此處分情況討論。y的左右兒子關係決定了x和z的大小關係。
因為我們要保證平衡樹的平衡,所以若y是z的右兒子,那麼x必定比z大,所以我們把x接在z的右兒子處,若y是z的左兒子反之。
繼續討論y與x的大小關係:顯而易見與「x與y的大小關係」相反,把y接在x後即可。
void rotate(int x)
這個操作是依靠rotate實現的。
分三種情況討論:
1.x和p是爺爺與兒子的關係,即只旋轉一次就可以到達位置:rotate(x)
2.son(x)和son(fa[x])不同:兩次rotate(x)
3.son(x)和son(fa[x])相同:rotate(fa[x]),rotate(x)
畫個圖就可以知道為什麼。
void splay(int x,int p)
if (!fa[x]) root=x;
}
利用二叉查詢樹的性質中序遍歷有序,我們每次比較當前節點和待查詢值的大小關係,決定下一步是往左子樹走還是往右子樹走。
int find_qq(int x)
int find_hj(int x)
找到x的前驅和後繼,將前驅旋轉到根(splay(qq,0)),後繼旋轉到根的右兒子(splay(hj,qq)),可以看出後繼的左兒子一定是空的,因為後繼的左兒子小於他並且大於前驅很明顯是不存在的。故將新元素插入到後繼的左兒子處。
void insert(int
x)
找到x的前驅,將其旋轉到根的位置,再找到x的後繼,旋轉到根的右兒子的位置,則根的右兒子的左兒子為需刪除的元素,清空根的右兒子的左指標即可。
void del(int
x)
查詢元素的前驅後繼,查詢元素排名,查詢排名為k的元素,插入/刪除元素等。 字尾平衡樹學習筆記
給定乙個空串s 操作1 代表在 s前加入乙個字母使之成為新s 操作2 代表在詢問在當前 s中有多少連續子串等於給定串t 假設我們已經有了串 s的字尾平衡樹 插入乙個字母c 我們用s i代表原串 s 從第 i個字元開始的字尾 則字尾 cs 與 任意乙個字尾 si 的大小關係可以用 c與s i 的第乙個...
回文樹學習小結
最近突然撿起了好久不搞的字串,研究了一下一直覺得很神奇的回文樹。相比於manacher,回文樹要顯得強大的多,同樣是接近o n 的複雜度,回文樹只需要多一點的空間,就可以實現許多用manacher實現起來非常複雜的功能。並且就 量而言,回文樹也足夠的簡短,作為處理回文串的工具,實在是非常的美妙。做了...
虛樹學習小結
其實虛樹這東西 不知道說什麼好 簡單易學呃 虛樹主要處理一種詢問總點數不超過o n 且每次詢問的那些點,在預處理之後,所求的值,只和他們,以及他們兩兩的lca有關 這裡有個顯然的結論,即m個點兩兩的lca不超過m 1個,將這m個點按dfs序排序之後相鄰兩點的m 1個lca就是這m個點兩兩的lca 建...