平衡的美 treap

来源:互联网 发布:苹果怎么卸载软件 编辑:程序博客网 时间:2024/06/12 00:53

简单易学的平衡树,虽然随机值要靠rp,但一般来说还是不会被卡的。

treap=tree+heap,treap有两个关键值,id和权值。

一般的二叉排序树难以维持自身平衡,容易退化成链,所以就有了id值。

id靠随机,对我们来说无实际意义,由堆序维护,听起来有点搞笑,但确实在大多数情况下能维护平衡。

w是节点自身属性,对我们来说有实际意义,遵循二叉排序树的规则,即根节点左子树均小于根,右子树均大于根,递归定义。

由于treap兼有二者特点,所以维护的时候,不能单一的按tree或heap来,于是诞生了旋转的操作,既能维护堆序,又能维护树序。

在treap中分为左旋和右旋两种:

右旋

         1                                                                                                    1

            \                                                                                                      \

              2                                                                                                     3 

           /     \                         ——————>                                             /      \

         3       4                                                                                           5         2

      /                                                                                                                       \   

   5                                                                                                                           4

左旋

           1                                                                                              1

            \                                                                                                 \

              2                                                                                               4

           /     \                         ——————>                                       /      \

         3       4                                                                                     2         5

                     \                                                                                  /                  

                       5                                                                           3                  

插入,先按二叉排序树插入,再维护id堆序(左旋,右旋实现,同时维护信息)

删除,找到指定节点,不断通过左旋右旋下沉,下沉至链节点(至少有一个子树为空)用其不为空子节点代替

基本操作就这些,还附带找k大,k小值等等操作

推荐模板http://blog.csdn.net/cjoilmd/article/details/6629062

lmd同学借助splay模板,写的非递归版treap,同时还有易错点。

总的来说,调试起来不是一般的麻烦,还是左偏树好调试。

const maxr=100000;var n,m,ss,ll,rr:longint;    size,l,r,w,id,rt,a:array[0..200000]of longint;    x,y,q,z,ans:array[0..500000]of longint;    check:longint;function max(x,y:longint):longint;begin if x>y then exit(x) else exit(y)end;function min(x,y:longint):longint;begin if x<y then exit(x) else exit(y)end;procedure right(x:longint);var y,z:longint;begin y:=rt[x];z:=rt[y]; if l[z]=y then l[z]:=x else r[z]:=x;rt[x]:=z; l[y]:=r[x];rt[r[x]]:=y; r[x]:=y;rt[y]:=x; size[x]:=size[y]; size[y]:=size[l[y]]+size[r[y]]+1end;procedure left(x:longint);var y,z:longint;begin y:=rt[x];z:=rt[y]; if l[z]=y then l[z]:=x else r[z]:=x;rt[x]:=z; r[y]:=l[x];rt[l[x]]:=y; l[x]:=y;rt[y]:=x; size[x]:=size[y]; size[y]:=size[l[y]]+size[r[y]]+1end;function ori(x,y:longint):longint;begin inc(ss);id[ss]:=random(maxr); w[ss]:=x;size[ss]:=1; l[ss]:=0;r[ss]:=0;rt[ss]:=y; ori:=ssend;procedure ins(p:longint);var x:longint;begin x:=1; while true do begin  inc(size[x]);  if p>w[x] then begin   if r[x]=0 then begin r[x]:=ori(p,x);x:=r[x];break end   else x:=r[x]  end  else begin   if l[x]=0 then begin l[x]:=ori(p,x);x:=l[x];break end   else x:=l[x]  end end; while id[x]<id[rt[x]] do  if l[rt[x]]=x then right(x) else left(x)end;procedure low(x:longint);var ll,rr:longint;begin ll:=l[x];rr:=r[x]; if id[ll]<id[rr] then right(ll) else left(rr)end;procedure del(p:longint);var x,y,z:longint;begin x:=1; while w[x]<>p do if w[x]<p then x:=r[x] else x:=l[x]; id[x]:=maxlongint; while (l[x]<>0)and(r[x]<>0) do low(x); y:=rt[x]; if l[x]=0 then z:=r[x] else z:=l[x]; if l[y]=x then l[y]:=z else r[y]:=z; if z<>0 then rt[z]:=y; while id[y]<>-maxlongint do begin  dec(size[y]);  y:=rt[y] end; dec(size[y])end;function findmin(q:longint):longint;var x:longint;begin x:=1;inc(q); while true do begin  if q=size[l[x]]+1 then exit(w[x])  else if q<=size[l[x]] then x:=l[x]  else begin   q:=q-size[l[x]]-1;   x:=r[x]  end endend;procedure work;var i,j:longint;begin rr:=0;x[0]:=x[1]; for i:=1 to m do begin  for j:=x[i-1] to min(x[i]-1,y[i-1]) do del(a[j]);  for j:=max(rr+1,x[i]) to y[i] do ins(a[j]);  ans[z[i]]:=findmin(q[i]);rr:=y[i] endend;procedure qsort(l,r:longint);var i,j,xx,yy,c:longint;begin i:=l;j:=r;xx:=x[(l+r)>>1];yy:=y[(l+r)>>1]; repeat  while (x[i]<xx)or((x[i]=xx)and(y[i]<yy)) do inc(i);  while (xx<x[j])or((xx=x[j])and(yy<y[j])) do dec(j);  if not(i>j) then begin   c:=x[i];x[i]:=x[j];x[j]:=c;   c:=y[i];y[i]:=y[j];y[j]:=c;   c:=q[i];q[i]:=q[j];q[j]:=c;   c:=z[i];z[i]:=z[j];z[j]:=c;   inc(i);dec(j)  end until i>j; if i<r then qsort(i,r); if l<j then qsort(l,j)end;procedure init;var i:longint;begin readln(n,m); for i:=1 to n do read(a[i]);readln; for i:=1 to m do begin  readln(x[i],y[i],q[i]);  z[i]:=i end; qsort(1,m); id[1]:=-maxlongint;w[1]:=-maxlongint;ss:=1; size[0]:=0; work; for i:=1 to m do writeln(ans[i])end;begin randomize; initend.