• bzoj1588,1208,1503


    进入splay tree的学习中;

    据说splay tree在理论上功能十分强大,好好学;

    splay首先一定是一棵BST,所以记不得的时候画个图就明白;

    首先总结一下splay基本的操作左旋,右旋;

    设节点x,其父节点y

    左旋:保留x的右子树,y的左子树,将y插入到x的x的左子树上并原来x的左子树接到y的右子树上,右旋反之;

    而Splay(x,s) (将x伸展为s的孩子)要分三种情况:

    若y是根节点,则x在哪儿往相反方向旋(左孩子右旋,右孩子左旋)

    若y的父节点是z,则若三点一线,先旋y再旋x

    否则一直旋x,在哪儿反向旋;具体画个图就知道了;

    核心就是在哪儿反向旋(是左孩子右旋,右孩子左旋)

    然后分析一下splay的几个操作;

    插入:很简单,按着BST的做法既可,之后把插入的元素伸展到根节点

    删除:分类讨论,若要删除的节点x无孩子,那么直接删除(这不废话吗);

          若x有1个孩子,那么把孩子接到父节点y上,然后删除;

          若x有2个孩子,那么,就有点麻烦了;

          首先找到x的后继p(第一个比x大的数),用其代替x,而本来p的孩子(只可能是有孩子),接到p父节点的左子树上

    找K大数,这个跟BST一样

    这三道平衡树的题目中,1503比较有思维难度(毕竟是noi)

    有两个问题比较难处理 1.怎么修改 2.怎么删除

    删除比较好办,把limit插入到tree中,然后删去左子树即可注意:这里相等的值要插入到左子树中,原因见后文)

    UPD:实际上相等的值处理应该在对应节点记录下出现次数即可

    修改难住了我,一开始想的是想线段树一样加一个lazy域,可觉得删除,伸展时还要维护实在太烦;

    后经人点醒,才明白完全可以只用一个全局变量temp来维护,

    temp表示整个序列(不只是当前,当然好像也不好表示当前……)都修改的值,于是

    相应的新加入的值就变为x-temp

    附代码:

      1 var lazy,a,fa,count:array[0..200010] of longint;
      2     son:array[0..200010,0..2] of longint;
      3     temp,m,n,lim,i,x,root,s:longint;
      4     c:char;
      5 
      6 procedure middle(i:longint);
      7   begin
      8     if son[i,1]<>0 then middle(son[i,1]);
      9     write(a[i]+temp,' ');
     10     if son[i,2]<>0 then middle(son[i,2]);
     11   end;
     12 
     13 procedure pushup(x:longint);       //一种很简便的维护子树方法,不需要记得这么烦
     14   begin
     15     count[x]:=count[son[x,1]]+count[son[x,2]]+1;
     16   end;
     17 
     18 procedure rotate(x,f:longint);
     19   var y,p:longint;
     20   begin
     21     y:=fa[x];
     22     fa[x]:=fa[y];
     23     if fa[y]<>0 then
     24     begin
     25       if son[fa[y],1]=y then son[fa[y],1]:=x
     26       else son[fa[y],2]:=x;
     27     end;
     28     son[y,3-f]:=son[x,f];
     29     if son[x,f]<>0 then fa[son[x,f]]:=y;
     30     fa[y]:=x;
     31     son[x,f]:=y;
     32     pushup(y);             //注意顺序
     33     pushup(x);
     34   end;
     35 
     36 procedure splay(x:longint);
     37   var y:longint;
     38   begin
     39     while fa[x]<>0 do
     40     begin
     41       y:=fa[x];
     42       if fa[y]=0 then
     43       begin
     44         if son[y,1]=x then
     45           rotate(x,2)
     46         else rotate(x,1);
     47       end
     48       else if son[fa[y],1]=y then
     49       begin
     50         if son[y,1]=x then
     51         begin
     52           rotate(y,2);
     53           rotate(x,2);
     54         end
     55         else begin
     56           rotate(x,1);
     57           rotate(x,2);
     58         end;
     59       end
     60       else if son[fa[y],2]=y then
     61       begin
     62         if son[y,1]=x then
     63         begin
     64           rotate(x,2);
     65           rotate(x,1);
     66         end
     67         else begin
     68           rotate(y,1);
     69           rotate(x,1);
     70         end;
     71       end;
     72     end;
     73     pushup(x);
     74     root:=x;
     75   end;
     76 
     77 procedure insert(x:longint);
     78   var p:longint;
     79   begin
     80     inc(m);
     81     son[m,1]:=0;
     82     son[m,2]:=0;
     83     count[m]:=1;
     84     a[m]:=x;
     85     if root=0 then
     86     begin
     87       root:=m;
     88       fa[m]:=0;
     89     end
     90     else begin
     91       p:=root;
     92       repeat
     93         inc(count[p]);
     94         if a[p]>=x then                 //注意:为什么要把等于的插入左子树,因为删除的时候删的是左子树,而如果比现在插入到右子树,根据之前的分析,将x旋转到根后,相等的父节点p会变成x的左子树(在哪就被旋转到相反到,相等时不需要删去)
     95         begin
     96           if son[p,1]=0 then break;
     97           p:=son[p,1];
     98         end
     99         else begin
    100           if son[p,2]=0 then break;
    101           p:=son[p,2];
    102         end;
    103       until false;
    104       fa[m]:=p;
    105       if a[p]>=x then son[p,1]:=m else son[p,2]:=m;
    106       splay(m);
    107     end;
    108   end;
    109 
    110 function kth(x:longint):longint;
    111   var p,h:longint;
    112   begin
    113     p:=root;
    114     h:=x;
    115     while h<>count[son[p,2]]+1 do
    116     begin
    117       if h>count[son[p,2]]+1 then
    118       begin
    119         h:=h-count[son[p,2]]-1;
    120         p:=son[p,1];
    121       end
    122       else p:=son[p,2];
    123     end;
    124     exit(p);
    125   end;
    126 
    127 begin
    128   readln(n,lim);
    129   temp:=0;
    130   for i:=1 to n do
    131   begin
    132     readln(c,x);
    133     if c='I' then
    134     begin
    135       if x>=lim then
    136       begin
    137         insert(x-temp);
    138         s:=s+1;
    139       end;
    140     end
    141     else if c='S' then
    142     begin
    143       temp:=temp-x;
    144       insert(lim-temp);
    145       if son[m,2]<>0 then             
    146       begin
    147         root:=son[m,2];
    148         fa[son[m,2]]:=0;
    149         m:=m-1;
    150       end
    151       else begin
    152         root:=0;
    153         fillchar(fa,sizeof(fa),0);
    154         fillchar(count,sizeof(count),0);
    155         fillchar(son,sizeof(son),0);
    156         m:=0;
    157       end;
    158     end
    159     else if c='A' then temp:=temp+x
    160     else if c='F' then
    161       if x>count[root] then writeln(-1) else writeln(a[kth(x)]+temp);   //注意打印的时候不忘+temp
    162  // middle(root);
    163   end;
    164   writeln(s-count[root]);         //count[root]就代表了整棵树的规模,即现有的人数
    165 end.
    bzoj1503

    另外附删除节点编号为x的子程序;

     1 function find(i,f:longint):longint;
     2   var p:longint;
     3   begin
     4     p:=son[i,f];
     5     while son[p,3-f]<>0 do p:=son[p,3-f];  //后缀:右孩子的最左节点
     6     find:=p;
     7   end;
     8 
     9 procedure delete(i:longint);
    10   var p,q:longint;
    11   begin
    12     dec(t);
    13     if t=0 then
    14     begin
    15       root:=0;
    16       f:=-1;
    17       exit;
    18     end;
    19     p:=0;
    20     if son[fa[i],1]=i then p:=1
    21     else if son[fa[i],2]=i then p:=2;
    22     if (son[i,1]<>0) and (son[i,2]<>0) then
    23     begin
    24       q:=find(i,2);
    25       if root=i then root:=q;
    26       if fa[q]<>i then      //当后继就是x的左孩子时,后继的孩子依然接在后继上
    27       begin
    28         son[fa[q],1]:=son[q,2];
    29         fa[son[q,2]]:=fa[q];
    30       end;
    31       fa[q]:=fa[i];
    32       son[fa[i],p]:=q;
    33       son[q,1]:=son[i,1];
    34       fa[son[q,1]]:=q;
    35       if son[i,2]<>q then         //小细节
    36       begin
    37         son[q,2]:=son[i,2];
    38         fa[son[q,2]]:=q;
    39       end;
    40       fa[i]:=-1;
    41       son[i,1]:=0;
    42       son[i,2]:=0;
    43     end
    44     else begin
    45       q:=0;
    46       if son[i,1]<>0 then q:=1;
    47       if son[i,2]<>0 then q:=2;
    48       if root=i then root:=son[i,q];
    49       if q=0 then son[fa[i],p]:=0
    50       else begin
    51         fa[son[i,q]]:=fa[i];
    52         son[fa[i],p]:=son[i,q];
    53       end;
    54       fa[i]:=-1;
    55     end;
    56   end;
    UPD:这是比较糟糕的写法……
  • 相关阅读:
    GregorianCalendar
    IfcDataOriginEnum
    Element
    IfcRecurrenceTypeEnum
    IfcDocumentInformation
    IfcTimeStamp
    IfcLibrarySelect
    IfcTimeOrRatioSelect
    Document
    IfcLanguageId
  • 原文地址:https://www.cnblogs.com/phile/p/4473297.html
Copyright © 2020-2023  润新知