进入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:这是比较糟糕的写法……

 

posted on 2014-01-18 21:54  acphile  阅读(160)  评论(0编辑  收藏  举报