首页 > 代码库 > fhqtreap的学习笔记

fhqtreap的学习笔记

一段时间之前学的fhqtreap……今天闲的没事稍微总结一下吧……学了fhq之后就再也不想写splay了。

fhqtreap的优点:速度快,代码简单,可以进行区间操作,而且也可以进行可持久化。

//学习这个首先得懂平衡树和可并堆。

首先要明确一点:fhqtreap本质上还是一个treap,也就是说它也是靠堆权值来维护树的平衡特性的。但是fhqtreap没有旋转,只有两个最简单的操作split(分裂)和merge(合并),通过这两个操作来维护平衡树的性质。我们用w表示平衡树里存的权值,f表示堆权值。

1.split(root,v,k1,k2)

这个操作是将一个根是root的树分裂成两个部分,将权值小于v的放在一棵平衡树里,大于w的放在另一颗平衡树里,最后返回的k1,k2值就是这两颗树的根。

下面我们考虑如何去划分。注意这里的k1,k2都是变参,k1表示小于v的树,k2表示大于v的树。

假使当前的节点是i,那么我们比较t[i].w和v的大小,如果t[i].w<=v,那么我们可以肯定,i的左子树也都小于v,但是对于右子树我们还不确定。这样的话,令k1=i,然后split(t[i].r,v,t[i].r,k2),相当于把i的右子树砍下来,递归处理i的右子树,拆分右子树,但是这时候k1的位置已经被i给占了,那么如果再有小于v的,我们就直接接到i的右孩子上(因为反正还是在一颗树里),这样满足二叉排序树的性质。同时我们是自顶而下拆、拼接的,所以不用考虑f也满足堆性质

如果t[i].w>v,同理,k2=i,split(t[i].l,v,k1,t[i].l)

这样我们调用split(root,v,k1,k2),就可以把一棵树拆成两个,类似于splay把分界点旋转到根一样,这样我们就可以在k1中寻找大于w的节点得信息,在k2中寻找小于w的节点的信息。

2.root=merge(k1,k2)

这个操作的意思是,把k1,k2两颗树变成一颗,并返回根节点的编号,注意这里k1的所有w都小于k2,因为这个操作通常是我们split然后处理好信息之后再把弄回一棵树。

学过可并堆应该就很好理解了。以为两棵树大小关系确定,我们只要考虑他们的堆权值。这里默认为大根堆。

对于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;

注意我们要保证每次递归处理时两颗子树的大小关系不变,所以顺序要注意。

 

下面我们就可以通过这两个基本的东西实现各种各样的操作了。

3.insert(v)

插入一个权值为v的点,把树按照v的权值成两个,再按照顺序合并回去。

//也有效率更高的插入方法,具体看代码

4.del(v)

删除权值为v的点,把树按照v分成两个k1,k2,再把k2按照v+1分成k3,k4,merge(merge(k1,t[k3].l),merge(t[k3].r,k4))

5.查询前驱后继

split(root,v,k1,k2),分别在k1,k2里面找最大值最小值

6.查询排名

split(root,v,k1,k2),排名是k1的size

7.区间操作

splite(root,l-1,k1,k2);splite(k2,r,k3,k4);k3为操作区间。

 

下面就是那个经典的普通平衡树的模板,稍稍有点不一样的是我把权值和划分值相等的的放在了第二颗树里

  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.

 

fhqtreap的学习笔记