HNOI2004宠物收养所(平衡树)

treap!

var i,n,x,y,ans,a,b,root,tot,ft:longint;
    l,r,s,v,hr:array[0..100000] of longint;
procedure r_rotate(var x:longint);
 var y:longint;
 begin
 y:=l[x];
 l[x]:=r[y];
 r[y]:=x;
 s[y]:=s[x];
 s[x]:=s[l[x]]+s[r[x]]+1;
 x:=y;
 end;
procedure l_rotate(var x:longint);
 var y:longint;
 begin
 y:=r[x];
 r[x]:=l[y];
 l[y]:=x;
 s[y]:=s[x];
 s[x]:=s[l[x]]+s[r[x]]+1;
 x:=y;
 end;
procedure insert(var k,key:longint);
 begin
 if k=0 then
  begin
   inc(tot);
   k:=tot;
   l[k]:=0;
   r[k]:=0;
   s[k]:=1;
   v[k]:=key;
   hr[k]:=random(maxlongint);
   exit;
  end;
 inc(s[k]);
 if key<=v[k] then
  begin
   insert(l[k],key);
   if hr[l[k]]>hr[k] then r_rotate(k);
  end
 else
  begin
   insert(r[k],key);
   if hr[r[k]]>hr[k] then l_rotate(k);
  end;
 end;
function delete(var k:longint;key:longint):longint;
 begin
 dec(s[k]);
 if (key=v[k]) or ((key<=v[k]) and (l[k]=0)) or ((key>v[k]) and (r[k]=0)) then
  begin
   delete:=v[k];
   if (l[k]=0) or (r[k]=0) then k:=l[k]+r[k]
   else v[k]:=delete(l[k],key+1);
   exit;
  end;
 if key<=v[k] then exit(delete(l[k],key))
 else exit(delete(r[k],key));
 end;
function pre(var k,key:longint):longint;
 begin
 if k=0 then exit(-1);
 if key<=v[k] then exit(pre(l[k],key))
 else
  begin
  pre:=pre(r[k],key);
  if pre=-1 then pre:=v[k];
  end;
 end;
function suc(var k,key:longint):longint;
 begin
 if k=0 then exit(-1);
 if key>v[k] then exit(suc(r[k],key))
 else
  begin
  suc:=suc(l[k],key);
  if suc=-1 then suc:=v[k];
  end;
 end;
procedure main;
 begin
 readln(n);
 ans:=0;tot:=0;root:=0;s[root]:=0;
 for i:=1 to n do
  begin
  readln(x,y);
  if x=ft then insert(root,y)
  else
   if s[root]=0 then
     begin
      ft:=x;
      insert(root,y);
     end
   else
    begin
    a:=pre(root,y);b:=suc(root,y);
    if a=-1 then a:=-maxlongint div 10;
    if b=-1 then b:=-maxlongint div 10;
    if abs(b-y)<abs(y-a) then
     begin
     ans:=(ans+abs(b-y)) mod 1000000;
     b:=delete(root,b);
     end
    else
     begin
     ans:=(ans+abs(y-a)) mod 1000000;
     a:=delete(root,a);
     end;
    end;
  end;
 writeln(ans);
 end;
begin
 main;
end.               

插入操作还有另一种写法:

procedure maintain(var t:longint;flag:boolean); 
    begin 
      if not flag then 
        if s[l[l[t]]]>s[r[t]] then 
          right_rotate(t) 
        else 
          if s[r[l[t]]]>s[r[t]] then 
            begin 
              left_rotate(l[t]); 
              right_rotate(t); 
            end 
          else exit 
      else 
        if s[r[r[t]]]>s[l[t]] then 
          left_rotate(t) 
        else 
          if s[l[r[t]]]>s[l[t]] then 
            begin 
              right_rotate(r[t]); 
              left_rotate(t); 
            end 
          else exit; 
      maintain(l[t],false); 
      maintain(r[t],true); 
      maintain(t,true); 
      maintain(t,false); 
    end; 
  procedure insert(var t,v:longint); 
    begin 
      if t=0 then 
        begin 
          inc(tt); 
          t:=tt; 
          s[t]:=1; 
          l[t]:=0; 
          r[t]:=0; 
          key[t]:=v; 
        end 
      else 
        begin 
          inc(s[t]); 
          if v<key[t] then insert(l[t],v) 
          else insert(r[t],v); 
          maintain(t,v>=key[t]); 
        end; 
    end;  

还需要注意的是,如果题目中明确要求求前驱,即小于它的最大数。那么pre操作的返回值应设为正在查找中的关键值,这样可以使整个操作的返回值不会与原值相同。

如果题中并没有说明必须不同,例如本题,一个数的前驱可以是这个数,那么pre的返回值应设为-1.

(update:20140810 这不叫另一种写法。。。这叫SBT。。。当时真无知)

原文地址:https://www.cnblogs.com/zyfzyf/p/3763132.html