線段樹不支援插入or刪除乙個數於是平衡樹產生了
常見平衡樹:treap(比sbt慢,好寫吧),sbt(快,比較好寫,有些功能不支援),splay(特別慢,複雜度當做根號n來用,功能強大,不好寫),rbt(紅黑樹,特別快),//替罪羊樹,朝鮮樹
晚上要講的不旋轉平衡樹:
節點的左兒子中的每乙個一定比他小,右兒子中的每乙個一定比他大
那麼它的中序遍歷是有序的
用下標建樹,那麼區間詢問的話就是求一棵子數和子樹根和領一棵子數的一部分
tree+heap,平衡樹和heap的性質是矛盾的,所以每個節點存乙個key和value
key值滿足heap性質,value滿足平衡樹的性質,這樣的樹叫做treap?
插入:插入的新節點的key值隨機,呼叫rand函式(這樣保證樹的深度一定是logn的)改變樹的形態使它重新滿足hea與平衡樹性質
操作1.merge:
merge(p1,p2):把以p1為根的treap和以p2為根的treap合併成乙個treap(p1中的所有制小於
操作2.split:
把以p為根的treap中拿出k小的數,組成乙個新treap
保證原先樹中的所有數》新樹中所有數
建乙個只有乙個點的樹(要插得數)例如(2.33)把(1,2)splay出來,再把新樹(2.33)和(1,2)merge起來,再把(1,2,2.33)和(4,5)merge 一下
如刪除(2.33),先把split(treap,3),此時把splay把(1,2)與(2.33,4,5)分離在split(treep2,1),此時(2.33)與(4,5)分離
在merge(treap1,treap3)合併即把(1,2),(4,5)合併,那麼2.33就沒了
實際操作
merge時,找key值最大的作為新treap的根,不是p1就是p2
1要是p1.p>=p2.p此時p1作為新根,那麼p1的左兒子不會變換,右子樹就是p1的右子樹和p2 merge 一下,即 merge(p1.r,p2);
2要是p2.p>p1.p此時p2作為新根,那麼p2的右兒子不會變換,左兒子就是p2的
左子樹 和 p1 mege 一下 即 merge(p2.l,p1);
split(p,k)幾點記錄value,key,l,r,size
p.l<-p->p.r;
1.要是k<=p.l.size 說明k小的點全在左子數,遞迴split(p.l,k);構成新樹的時候直接把split後剩下的左子樹接到p根上就好了
2.k=p.l.size+1;,返回兩棵樹(p.l-p,p.r)
3.k>p.l.siz+1,左邊已經全不要,那麼就split(p.r,k-p.l.size-1);
返回兩棵樹(p.l-p-p.r,剩餘p.r)
int merge(int x,int y)
}
按照權值進行split,split出的x數(所有節點權值小於a)的大小+1,就是a的rank
split(root,a-1,x,y);
printf("%d\n",siz[x]+1);
root=merge(x,y);
插入乙個新節點
int make_new(int v)
刪除乙個數,把這個數split出來,然後將另外兩顆split出來的樹merge起來
split(root,a,x,z);
split(x,a-1,x,y);
y=merge(tree[y][0],tree[y][1]);
root=merge(merge(x,y),z);
查詢a的前驅
查詢按照a作為標準split出的x子樹中的最大值
split(root,a-1,x,y);
printf("%d\n",val[kth(x,siz[x])]);
root=merge(x,y);
查詢a的後繼
查詢按照a作為標準split出的y子樹中的最小值
split(root,a,x,y);
printf("%d\n",val[kth(y,1)]);
root=merge(x,y);
區間操作
總結,利用split與merge完成各種操作
無旋treap 文藝平衡樹
因為需要用到區間修改,所以該用splay 尚未填坑 或者無旋treap 剛剛填上 最開始的建樹用到了建笛卡爾樹的方法,把id大於當前點的點不斷出棧,又因為這道題的點是按序入棧的,所以當它無法讓更多點出棧時,他就是棧首的右子樹,而最後乙個出棧的點,就是當前點的左子樹。顯然root zhan 1 inc...
平衡樹之Treap
乙個集合支援快速插入 刪除乙個數字。支援快速查詢乙個數字在所有已插入數字中的排名。支援刪除大小在某乙個區間內的數字。動態維護乙個數列。可以在數列的任何位置插入刪除,求區間和,min,max,進行區間翻轉 這就需要用到二叉查詢樹 binary search tree 性質 這是一棵二叉樹。對於任意乙個...
非旋Treap 學習筆記
今天學習了一下非旋tr eap 聽說效率很高而且可持久化 一臉懵逼qa q 非旋treap主要是兩個操作sp lit 和me rge 下面簡單描述一下 得先會tr eap 啊 va l 點的值 ke y ra nd的值 sp lit 就是我們把原tr eap 拆成兩個tr eap x,y 比如以va...