Treap初步入門

2022-05-25 13:42:13 字數 2919 閱讀 2717

樹堆,在資料結構中也稱\(\rm treap\),是指有乙個隨機附加域滿足堆的性質的二叉搜尋樹,其結構相當於以隨機資料插入的二叉搜尋樹。其基本操作的期望時間複雜度為\(\rm o(logn)\)。相對於其他的平衡二叉搜尋樹,\(\rm treap\)的特點是實現簡單,且能基本實現隨機平衡的結構。

\(\rm q\):為什麼要用\(\rm treap\)?

\(\rm a\):

這我們不得不談到\(\rm tree\)——二叉排序樹了。

二叉排序樹,是指根的左兒子比根小,右兒子比根大,且左右子樹均為二叉排序樹的樹 通俗來說,就是左子樹全部比根小,右子樹全部比根大,如圖:

這時候,我們要插入乙個節點,就不斷地判斷與根的大小關係(假設沒有節點相同):

比根小,去左子樹

比根大,去右子樹

直到來到乙個空樹,插入:

刪除節點:

如果乙個節點是葉子節點,直接銷毀

否則,如果這個節點有乙個子節點,直接將其連線到該節點的父親

否則,沿著右子樹的根一路向左到底,然後用那個值替換掉要刪除的節點,例如我們要刪\(7\):

因為這個點必定小於右子樹的其他值,且大於左子樹的全部數,所以他是作為根的最好人選

接下來,交換\(8\)和\(7\),然後銷毀\(7\):

查詢\(x\)的排名:

這個很簡單,檢視\(x\)與根的大小關係,如果相等,排名為左子樹元素個數\(+1\)

比根小,遞迴查詢他在左子樹的排名,排名為他在左子樹的排名,空樹排名為\(0\)

比根大,遞迴查詢他在右子樹的排名,排名為右子樹的排名+左子樹元素個數\(+1\)

查詢排名為\(x\)的數:

這個也很好理解,判斷左子樹元素個數是否大於等於之

如果是就在左子樹找

否則,如果剛好為左子樹元素個數\(+1\),就是根

如果大於左子樹元素個數\(+1\),則必定在右子樹,這個和查詢x排名對照起來就很好理解

查詢x的前驅(求權值比\(x\)小的最大節點):

空節點返回\(\rm -inf\)

如果根的權值小於等於\(x\),就在左子樹找

否則,取根和右子樹查詢結果的最大值(我們要求最大節點)

查詢x的後繼(求權值比\(x\)大的最小節點):

空節點返回\(\rm inf\)

如果根的權值大於等於\(x\),就去右子樹

否則,取根和左子樹查詢結果的最小值(我們要求最小節點)

其實上面的前驅後繼對照看就很好記

這時候細心的人會發現,這六個操作不就是剛剛上面講的\(\rm treap\)支援的操作嗎?

好吧,那如果是這樣我們還寫個\(\rm treap\)幹什麼?

原因看下圖

退化成一條鏈了!

恐怕是藥丸了,雖然一般情況下二叉排序樹複雜度不錯,是 \(\rm o(logn)\)

但是,不排除有喪心病狂的出題人故意卡你的情況,這時候複雜度為 \(\rm o(n)\)

要怎麼辦呢?

堆!你值得擁有!

堆的應用並沒有大的區別,請大家自行理解

洛谷p3369 【模板】普通平衡樹

\(\rm my\)

\(\rm code\)

#include#include#include#define inf 0x7fffffff

int n,tot,opt,xx,root,seed;

struct treapt[100005];

using namespace std;

inline int new(int num)

inline void update(int x)

inline void build()

inline void zag(int &x)

inline void zig(int &x)

void insert(int &p,int x)

if (x==t[p].val)

if (x1)

if (t[p].l||t[p].r)

else

update(p);

} else p=0;

return;

}x=x) return getvalbyrank(t[p].l,x);

if (t[t[p].l].size+t[p].cnt>=x) return t[p].val;

return getvalbyrank(t[p].r,x-t[t[p].l].size-t[p].cnt);

}int getrankbyval(int p,int x)

break;

}if (t[p].valt[ans].val) ans=p;

p=xx&&t[p].val'9')

while (ch>='0'&&ch<='9')

return f*x;

}

判斷條件中的\(\)不要搞反

初始化\(\rm treap\)中的\(dat\)要用\(\rm c++\)自帶的\(rand()\)!!!否則反而會\(\rm tle\)!!!

Linux初步入門

對於linux的初步入門以前都要對計算機概論有一些了解。1.計算機 接收使用者輸入指令與資料,經過 處理器的資料與邏輯單元運算處理後,以產生或儲存成有用的資訊。2.計算機五大硬體 輸入單元 輸出單元 cpu內部的控制單元 算術邏輯單元與記憶體五大部分。3.cpu種類 精簡指令集 risc 與複雜指令...

python初步入門

help obj 檢視幫助 import 檔名 匯入乙個檔案 from 檔名 import 方法名 匯入檔案中的乙個方法 dir var 檢視變數屬性和方法 none 空物件 邏輯運算 and or not elif elseif 沒有switch語句 沒有三目運算子 for迴圈 for 變數 in...

初步入門練習篇

n 0 whilen 100 ifn 3 0 andn 5 0 print n,是3和5的倍數 elifn 5 0 print n,是5的倍數 elifn 3 0 print n,是3的倍數 elifn 11 0 breakn n 1 else print 迴圈結束 nums range 5 for...