伸展树算法

  • 格式:docx
  • 大小:25.40 KB
  • 文档页数:16

伸展树学习

1、access(i,t):如果i在树t中,则返回指向它的指针,否则返回空指针。为了实现access(i,t),可以从树t的根部向下查找i。如果

查找操作遇到了一个含有i的节点x,就在x处进行splay操作,并返回指向x的指针,访问结束。如果遇到了空指针,表示i不在树中,此时就在最后一个非 空节点处进行splay操作,然后返回空指针。如果树是空的,将忽略掉splay操作。

2、insert(i,t):将条目i插入树t中(假设其尚不存在)。为了实现insert(i,t),首先执行split(i,t),然后把t换成一个由新的包含有i的根节点组成的树,这个根节点的左右子树分别是split返回的树t1和t2。

3、delete(i,t):从树t中删除条目i(假设其已经存在)。为了实现delete(i,t),首先执行access(i,t),然后把t换成其左子树和右子树join之后的新树。

4、join(t1,t2):将树t1和t2合并成一棵树,其中包含之前两棵树的所有条目,并返回合并之后的树。这个操作假设t1中的所有条目都小于t2 中的条目,操作完成之后会销毁t1和t2。为了实现join(t1,t2),首先访问t1中最大的条目i。访问结束之后,t1的根节点中包含的就是i,它 的右孩子显然为空。于是把t2作为这个根节点的右子树并返回完成之后的新树即可实现join操作。

5、split(i,t):构建并返回两棵树t1和t2,其中t1包含t中所有小于等于i的条目,t2包含t中所有大于i的条目。操作完成之后销毁t。为 了实现split(i,t),首先执行access(i,t),然后根据新根节点中的值是大于还是小于等于i来切断这个根节点的左链接或右链接,并返回形 成的两棵树。

另外insert和delete方法有更好的实现,时间复杂度更小:

1、insert(i, t):查找i,把遇到的空指针替换成一个含有i的新节点,然后再在新节点处对树进行splay操作。

2、delete(i, t):查找含有i的节点,设此节点为x,其父节点为y。把x的左右子树合并之后替换掉x,然后再从y处进行splay操作。

const

maxn=100000+5;

oo=maxlongint shr 1;

var

n,root,task:longint;

a,son,l,r,b1,b2,mi:array [0..maxn+maxn] of longint;

function min(x,y:longint):longint;

begin

if x

end;

procedureinit;

var

i:longint;

begin

readln(n);

root:=n+2;

for i:=2 to n+1 do

begin

readln(a[i]);

l[i]:=i-1; son[i]:=i;

mi[i]:=a[i];

end;

l[n+2]:=n+1;

son[1]:=1;

son[n+2]:=n+2;

mi[0]:=oo;

mi[1]:=oo;

mi[n+2]:=oo;

a[1]:=oo;

a[n+2]:=oo;

n:=n+2;

end;

procedure update(i:longint);

begin

son[i]:=son[l[i]]+son[r[i]]+1;

mi[i]:=min(min(mi[l[i]],mi[r[i]]),a[i]);

end;

procedure left(var i:longint);

var

j:longint;

begin

j:=r[i];

r[i]:=l[j];

l[j]:=i;

update(i);

update(j);

i:=j;

end;

procedure right(var i:longint);

var

j:longint;

begin

j:=l[i];

l[i]:=r[j];

r[j]:=i;

update(i);

update(j);

i:=j;

end;

procedure put1(i,j:longint);

begin

ifi=0 then exit;

a[i]:=a[i]+j;

mi[i]:=mi[i]+j;

b1[i]:=b1[i]+j;

end;

procedure put2(i:longint);

var

z:longint;

begin

ifi=0 then exit;

z:=l[i];

l[i]:=r[i];

r[i]:=z;

b2[i]:=1-b2[i];

end;

procedure up(var i:longint;k:longint);

begin

ifi=0 then exit;

if b1[i]>0 then

begin

put1(l[i],b1[i]);

put1(r[i],b1[i]);

b1[i]:=0;

end;

if b2[i]>0 then

begin

put2(l[i]);

put2(r[i]);

b2[i]:=0;

end;

if k<=son[l[i]] then

begin

up(l[i],k);

right(i);

end else

if k>son[l[i]]+1 then

begin

up(r[i],k-son[l[i]]-1);

left(i);

end; end;

procedure work;

var

i,j,k,kk,c,z:longint;

st:string;

begin

readln(task);

for task:=1 to task do

begin

readln(st);

whilest[length(st)]=' ' do delete(st,length(st),1);

st:=st+' ';

if (st[1]='A') then c:=1 else

if (st[1]='R') and (st[4]='E') then c:=2 else

if (st[1]='R') and (st[4]='O') then c:=3 else

if (st[1]='I') then c:=4 else

if (st[1]='D') then c:=5 else c:=6;

delete(st,1,pos(' ',st));

val(copy(st,1,pos(' ',st)-1),i,z);

delete(st,1,pos(' ',st));

if length(st)>1 then

begin

val(copy(st,1,pos(' ',st)-1),j,z);

delete(st,1,pos(' ',st));

if length(st)>1 then val(copy(st,1,length(st)-1),k,z);

end;

case c of

1:begin

inc(i);

inc(j);

up(root,i-1);

up(root,j+1);

put1(r[l[root]],k);

end;

2:begin

inc(i);inc(j);

up(root,i-1);up(root,j+1);

put2(r[l[root]]);

end;

3:begin

inc(i);

inc(j);

up(root,i-1); up(root,j+1);

k:=k mod (j-i+1);

if k>0 then

begin

kk:=r[l[root]];

up(kk,j-k-i+1);

up(r[kk],k);

z:=r[kk];

r[z]:=kk;

r[l[root]]:=z;

r[kk]:=0;

update(r[z]);

update(z);

end;

end;

4:begin

inc(i);

inc(n);

a[n]:=j;

mi[n]:=j;

j:=n;

up(root,i);{把i旋转到root处}

r[j]:=r[root];

r[root]:=j;

update(j);

update(root);

end;

5:begin

inc(i);

up(root,i);{把以root为根的树中的第i小的旋转到root处}

up(r[root],1);{把以r[root]为根的树中的第i小的旋转到r[root] 处}

l[r[root]]:=l[root];

root:=r[root];

update(root);

end;

6:begin

inc(i);

inc(j);

up(root,i-1);

up(root,j+1);

writeln(mi[r[l[root]]]);

end;

end;

end;