首先說一下,
這個東西可以搞一切bst,treap,splay所能搞的東西
今天心血來潮,
想搞一搞平衡樹,
思路比較好理解,但是
**量。。。。。。。。
一看就頭大,,
然後,在洛谷翻題解的時候無意間看到了遠航之曲發的一篇非常短小精悍的題解,
於是就學了一下
這個東西的學名應該是叫做fhq treap,應該是treap的強化版。
整個資料結構中只有兩個操作:
1.分離(split) 就是把一棵樹分成兩個樹
2.合併(merge)把兩棵樹合成一棵樹
對於fhq 的兩種操作的原理以及實現,
我在這裡就不去贅述,
大家可以去看一下遠航之曲寫的部落格
在這裡我主要是在講解一下**的具體實現(當然也有可能不對。。)
先說一下各個陣列的含義:
1int ch[maxn][3];//
0左孩子 1右孩子
2int val[maxn];//
每乙個點的權值
3int pri[maxn];//
隨機生成的附件權值
4int siz[maxn];//
以i為節點的樹的節點數量
5int sz;//
總結點的數量
然後來分別說明一下六中操作的實現
1.插入:
split(root,a,x,y);root=merge(merge(x,new_node(a)),y);
這個比較好理解,我們先把樹分為x,y兩部分,然後把新的節點a看做是一棵樹,先與x合併,合併完之後將合併的整體與y合併
2.刪除
1split(root,a,x,z);
2 split(x,a-1
,x,y);
3 y=merge(ch[y][0],ch[y][1
]);4 root=merge(merge(x,y),z);
首先我們把樹分為x和z兩部分
那麼x樹中的最大權值為a
再把x分為x和y兩部分。
此時x中的最大權值為a-1,且權值為a的節點一定是y的根節點。
然後我們可以無視y的根節點,直接把y的左右孩子合併起來,這樣就成功的刪除了根節點,
最後再把x,y,z合併起來就好
3.查詢a的排名
1 split(root,a-1,x,y);
2 printf("
%d\n
",siz[x]+1
);3 root=merge(x,y);
我們首先按照a-1的權值把樹分開。
那麼x樹中最大的應該是a-1。
那麼a的排名就是siz[x]+1
4.查詢排名為a的數
1 printf("
%d\n
",val[kth(root,a)]);
直接呼叫查詢排名的函式即可,
這個函式應該比較好理解。。
5.求x的前驅(前驅定義為小於a,且最大的數)
1 split(root,a-1,x,y);
2 printf("
%d\n
",val[kth(x,siz[x])]);
3 root=merge(x,y);
因為要小於a,那麼我們按照a-1的權值劃分,
x中最大的一定是<=a-1的,
所以我們直接輸出x中最大的數就好,
(這裡有乙個小技巧,因為siz儲存的是節點的數目,然後根據二叉查詢樹的性質,編號最大的就是值最大的)
6.求x的後繼(後繼定義為大於x,且最小的數)
1split(root,a,x,y);
2 printf("
%d\n
",val[kth(y,1
)]);
3 root=merge(x,y);
和上面的原理類似,
留給大家思考,
不懂的再問我。
1 #include2 #include3 #include4 #include5 #include6 #include7 #include8using
namespace
std;
9const
int maxn=100001;10
static
void read(int &n)
1114
while(c>='
0'&&c<='9')
15 flag==1?n=-x:n=x;16}
17int ch[maxn][3];//
0左孩子 1右孩子
18int val[maxn];//
每乙個點的權值
19int pri[maxn];//
隨機生成的附件權值
20int siz[maxn];//
以i為節點的樹的節點數量
21int sz;//
總結點的數量
22void update(int
x)23 26
int new_node(int
v)27
33int merge(int x,int y)//
合併 34 42
else
4348}49
void split(int now,int k,int &x,int &y)50
60}61int kth(int now,int k)//
查詢排名
6272}73
intmain()
7488
else
if(how==2)//
刪除x
8995
else
if(how==3)//
查詢x的排名
96101
else
if(how==4)//
查詢排名為x的數
102105
else
if(how==5)//
求x的前驅
106111
else
if(how==6)//
求x的後繼
112117
}118
return0;
119 }
最後說一下,fhq其實是可以處理區間問題的,
主要就是先把r+1的拆出來,然後把l的拆出來。
但是有些細節問題特別神奇,至今沒有搞懂。
如果你會的話希望你能給本蒟蒻講一下。
謝謝
學習筆記 FHQ Treap
fhq treap 發明者範浩強年年noi金牌 是一種神奇的資料結構,也叫非旋treap,它不像treap zig zag搞不清楚 所以叫非旋嘛 也不像splay完全看不懂,而且它能完成treap與splay能完成的所有事,短,理解也容易。fhq treap和treap很像,都是給每個節點乙個隨機的...
Fhq Treap 學習筆記
fhq treap 是一種平衡樹,又稱非旋 treap,其特點可以從名字裡明顯看出。fhq treap 具有 短 拓展性強的優點,在 oi 中的用途較廣。對於插入 v 的操作,我們把 treap 拆成 leq v 1 和 geq v 兩部分,接下來把 v 和 leq v 1 的部分合併,再把這一部分...
學習筆記 fhq treap
不需要旋轉,只需要 split 和合併 merge 就可以支援 splay 的所有操作。非常好寫,非常好調。並且支援可持久化 雖然我不會 對於每個點需要乙個附加權值,根據這個附加權值維護乙個小根堆,這樣這棵樹平衡與否是由這個附加權值決定的,那麼這個權值該怎麼取呢?隨機!這樣 treap 就大概是平衡...