fhqtreap的学习笔记
一段時間之前學(xué)的fhqtreap……今天閑的沒事稍微總結(jié)一下吧……學(xué)了fhq之后就再也不想寫splay了。
fhqtreap的優(yōu)點:速度快,代碼簡單,可以進行區(qū)間操作,而且也可以進行可持久化。
//學(xué)習這個首先得懂平衡樹和可并堆。
首先要明確一點:fhqtreap本質(zhì)上還是一個treap,也就是說它也是靠堆權(quán)值來維護樹的平衡特性的。但是fhqtreap沒有旋轉(zhuǎn),只有兩個最簡單的操作split(分裂)和merge(合并),通過這兩個操作來維護平衡樹的性質(zhì)。我們用w表示平衡樹里存的權(quán)值,f表示堆權(quán)值。
1.split(i,v,k1,k2)
這個操作是將一個根是i的(子)樹分裂成兩個部分,將權(quán)值小于v的放在一棵平衡樹k1里,大于w的放在另一顆平衡樹k2里。
如果我們調(diào)用split(root,v,k1,k2),就是將整棵樹分成兩棵樹,權(quán)值小于v的在以k1為根的樹里,大于v的在以k2為根的樹里。這樣我們就可以方便進行其他操作了。
下面我們考慮如何去劃分。注意這里的k1,k2都是變參,因為是變參,所以可以理解為現(xiàn)在這兩顆樹上要插新節(jié)點的空位
假使當前的節(jié)點是i,那么我們比較t[i].w和v的大小,如果t[i].w<v,那么我們可以肯定,i的左子樹也都小于v,但是對于右子樹我們還不確定。這樣的話,令k1=i,把i插到k1這個空位上,而i的左子樹應(yīng)該在這顆平衡樹中,所以保留。然后split(t[i].r,v,t[i].r,k2),相當于把i的右子樹砍下來(因為右子樹不一定在i所在的平衡樹),遞歸處理i的右子樹,拆分右子樹,這時候k1的空位已經(jīng)被i給占了,但是i的右子樹被砍掉了,這樣i的右孩子是一個空位,那么如果再有小于v的,我們就直接接到i的右孩子上,這樣滿足二叉排序樹的性質(zhì)。同時我們是自頂而下拆、拼接的,所以不用考慮f也滿足堆性質(zhì)
如果t[i].w>=v,同理,k2=i,split(t[i].l,v,k1,t[i].l)
這樣我們調(diào)用split(root,v,k1,k2),就可以把一棵樹拆成兩個,類似于splay把分界點旋轉(zhuǎn)到根一樣,這樣我們就可以在k1中尋找大于w的節(jié)點得信息,在k2中尋找小于w的節(jié)點的信息。
2.root=merge(k1,k2)
這個操作的意思是,把k1,k2兩顆樹變成一顆,并返回根節(jié)點的編號,注意這里k1的所有w都小于k2,因為這個操作通常是我們split然后處理好信息之后再把弄回一棵樹。
學(xué)過可并堆應(yīng)該就很好理解了。以為兩棵樹大小關(guān)系確定,我們只要考慮他們的堆權(quán)值。這里默認為大根堆。
對于t[k1].f>t[k2].f,t[k1].r=merge(t[k1].r,k2);return k1;
對于t[k1].f<t[k2].f,t[k2].l=merge(k1,t[k2].l);return k2;
注意我們要保證每次遞歸處理時兩顆子樹的大小關(guān)系不變,所以順序要注意。
?
下面我們就可以通過這兩個基本的東西實現(xiàn)各種各樣的操作了。
3.insert(v)
插入一個權(quán)值為v的點,把樹按照v的權(quán)值成兩個,再按照順序合并回去。
//也有效率更高的插入方法,具體看代碼
4.del(v)
刪除權(quán)值為v的點,把樹按照v分成兩個k1,k2,再把k2按照v+1分成k3,k4,merge(merge(k1,t[k3].l),merge(t[k3].r,k4))
5.查詢前驅(qū)后繼
split(root,v,k1,k2),分別在k1,k2里面找最大值最小值
6.查詢排名
split(root,v,k1,k2),排名是k1的size
7.區(qū)間操作
splite(root,l-1,k1,k2);splite(k2,r,k3,k4);k3為操作區(qū)間。
?
下面就是那個經(jīng)典的普通平衡樹的模板
1 /************************************************************** 2 Problem: 3224 3 User: 1090900715 4 Language: Pascal 5 Result: Accepted 6 Time:800 ms 7 Memory:2180 kb 8 ****************************************************************/ 9 10 program j01; 11 type xx=record l,r,f,w,size:longint; end; 12 var t:array[0..100086]of xx; 13 n,i,op,x,k1,k2,k3,k4,root,tt:longint; 14 15 procedure update(i:longint); 16 begin 17 if i=0 then exit; 18 t[i].size:=t[t[i].l].size+t[t[i].r].size+1; 19 end; 20 21 function merge(x,y:longint):longint; 22 begin 23 if (x=0)or(y=0) then exit(x+y); 24 if t[x].f>t[y].f then 25 begin 26 t[x].r:=merge(t[x].r,y); 27 update(x);exit(x); 28 end else 29 begin 30 t[y].l:=merge(x,t[y].l); 31 update(y);exit(y); 32 end; 33 end; 34 35 procedure splite(i,x:longint;var k1,k2:longint); 36 begin 37 if i=0 then 38 begin 39 k1:=0;k2:=0;exit; 40 end; 41 if t[i].w<x then 42 begin 43 k1:=i;splite(t[i].r,x,t[i].r,k2); 44 end else 45 begin 46 k2:=i;splite(t[i].l,x,k1,t[i].l); 47 end; 48 update(i); 49 end; 50 51 function insert(i,k:longint):longint; 52 begin 53 if i=0 then exit(k); 54 if t[i].f>t[k].f then 55 begin 56 if t[i].w<t[k].w then t[i].r:=insert(t[i].r,k) 57 else t[i].l:=insert(t[i].l,k); 58 update(i);exit(i); 59 end; 60 splite(i,t[k].w,t[k].l,t[k].r);update(k);exit(k); 61 end; 62 63 function find(i,x:longint):longint; 64 begin 65 if t[t[i].l].size+1=x then exit(t[i].w); 66 if t[t[i].l].size>=x then exit(find(t[i].l,x)) 67 else exit(find(t[i].r,x-t[t[i].l].size-1)); 68 end; 69 70 function findpre(i:longint):longint; 71 begin 72 while t[i].r<>0 do i:=t[i].r;exit(t[i].w); 73 end; 74 75 function findnex(i:longint):longint; 76 begin 77 while t[i].l<>0 do i:=t[i].l;exit(t[i].w); 78 end; 79 80 begin 81 readln(n);tt:=0;root:=0; 82 randomize; 83 for i:=1 to n do 84 begin 85 readln(op,x); 86 if op=1 then 87 begin 88 inc(tt); 89 t[tt].w:=x;t[tt].f:=random(maxlongint);t[tt].size:=1; 90 root:=insert(root,tt); 91 end; 92 if op=2 then 93 begin 94 splite(root,x,k1,k2);splite(k2,x+1,k2,k3); 95 root:=merge(merge(k1,t[k2].l),merge(t[k2].r,k3)); 96 end; 97 if op=3 then 98 begin 99 splite(root,x,k1,k2);writeln(t[k1].size+1); 100 root:=merge(k1,k2); 101 end; 102 if op=4 then writeln(find(root,x)); 103 if op=5 then 104 begin 105 splite(root,x,k1,k2);writeln(findpre(k1)); 106 root:=merge(k1,k2); 107 end; 108 if op=6 then 109 begin 110 splite(root,x+1,k1,k2); 111 writeln(findnex(k2)); 112 root:=merge(k1,k2); 113 end; 114 end; 115 end.?
轉(zhuǎn)載于:https://www.cnblogs.com/oldjang/p/6291467.html
總結(jié)
以上是生活随笔為你收集整理的fhqtreap的学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue-cli 官方模板webpack-
- 下一篇: BZOJ 1568 李超线段树