http://www.lydsy.com/JudgeOnline/problem.php?id=1269
1269: [AHOI2006]文本编辑器editor Input Output Sample Input Sample Output
对输入数据我们有如下假定: MOVE操作不超过50 000个,INSERT、DELETE和ROTATE操作作的总个数不超过6 000,GET操作不超过20 000个,PREV和NEXT操作的总个数不超过20 000。 所有INSERT插入的字符数之和不超过2M(1M=1 024*1 024)。 DELETE操作、ROTATE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。 输入文件没有错误。
|
裸Splay。有几个问题导致调了很长时间……
1、update旋转标记时千万不要忘记清空自身标记,同时子树的标记应该取反,而非直接赋false
2、update最好过程内直接操作本身、左右子树,这样不容易写错。
3、pushup时一定要记得更新其父亲各节点!
program editor;
//Splay Tree
//By HT 2012/12
//BZOJ P1269
//AHOI2004 Editor
{$DEFINE INDEBUG}
Type
node=longint;
rec=record
lch,rch,f,s:longint;
w:char;
ro:boolean;
end;
Var
q:array[0..2000000] of rec;
ss:array[0..10000] of char;
h,null,now:node;
top,i,j,k,n:longint;
c:char;
Procedure fopen;
begin
assign(input,'editor.in');
assign(output,'editor.out');
reset(input);
rewrite(output);
end;
Procedure fclose;
begin
close(input);
close(output);
end;
Function mmin(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
Procedure new(var p:node);
begin
inc(top);
p:=top;
end;
Procedure pushup(P:node);
begin
while p<>null do
begin
q[p].s:=q[q[p].lch].s+q[q[p].rch].s+1;
p:=q[p].f;
end;
end;
Procedure oldupdate(P:node);
var
y:node;
begin
if p=null then exit;
if q[p].ro then
begin
y:=q[p].lch;
q[p].lch:=q[p].rch;
q[p].rch:=y;
if q[p].lch<>null then q[q[p].lch].ro:=not q[q[p].lch].ro;
if q[p].rch<>null then q[q[p].rch].ro:=not q[q[p].rch].ro;
q[p].ro:=false;
end;
end;
Procedure update(P:node);
begin
oldupdate(q[p].lch);
oldupdate(q[p].rch);
oldupdate(p);
end;
Procedure zig(P:node);// LeftRonate
var
newroot:node;
begin
if p=null then exit;
update(p);
if q[p].rch=null then exit;
newroot:=q[p].rch;
q[newroot].f:=q[p].f;
if q[p].f<>null then
if q[q[p].f].lch=p then
q[q[p].f].lch:=newroot else
q[q[p].f].rch:=newroot
else
h:=newroot;
q[p].rch:=q[newroot].lch;
if q[p].rch<>null then
q[q[p].rch].f:=p;
q[newroot].lch:=p;
q[p].f:=newroot;
pushup(p);
pushup(newroot);
end;
Procedure zag(P:node);//RightRonate
var
newroot:node;
begin
if p=null then exit;
update(p);
if q[p].lch=null then exit;
newroot:=q[p].lch;
q[newroot].f:=q[p].f;
if q[p].f<>null then
if q[q[p].f].lch=p then
q[q[p].f].lch:=newroot else
q[q[p].f].rch:=newroot
else
h:=newroot;
q[p].lch:=q[newroot].rch;
if q[p].lch<>null then
q[q[p].lch].f:=p;
q[newroot].rch:=p;
q[p].f:=newroot;
pushup(p);
pushup(newroot);
end;
Procedure Splay(P,tar:node);
var
x,y,z:node;
begin
if p=null then exit;
x:=p;
while q[x].f<>tar do
begin
y:=q[x].f;
z:=q[y].f;
update(z);
update(y);
update(x);
if z=tar then
begin
if q[y].lch=x then zag(y) else zig(y);
exit;
end;
if (q[z].lch=y) and (q[y].lch=x) then
begin
zag(z);
zag(y);
end else
if (q[z].rch=y) and (q[y].rch=x) then
begin
zig(z);
zig(y);
end else
if (q[z].lch=y) and (q[y].rch=x) then
begin
zig(y);
zag(z);
end else
begin
zag(y);
zig(z);
end;
end;
end;
Function kth(P:longint):node;
begin
kth:=h;
update(kth);
if p>q[h].s then p:=q[h].s;
while q[kth].s>1 do
begin
if q[q[kth].lch].s+1=p then exit;
if p<q[q[kth].lch].s+1 then kth:=q[kth].lch else
begin
dec(p,q[q[kth].lch].s+1);
kth:=q[kth].rch;
end;
update(kth);
end;
end;
Function buildtree(pl,pr:longint):node;
var
mid:longint;
ans:node;
begin
if pr<pl then exit(null);
if pl=pr then
begin
new(ans);
with q[ans] do
begin
s:=1;
w:=ss[pl];
lch:=null;
rch:=null;
f:=null;
ro:=false;
end;
exit(ans);
end;
mid:=(pl+pr) div 2;
new(ans);
with q[ans] do
begin
s:=pr-pl+1;
w:=ss[mid];
ro:=false;
lch:=buildtree(pl,mid-1);
rch:=buildtree(mid+1,pr);
if lch<>null then
q[lch].f:=ans;
if rch<>null then
q[rch].f:=ans;
exit(ans);
end;
end;
Procedure Insert(k:longint);
var
p:node;
begin
p:=now;
update(p);
if q[p].rch=null then
begin
q[p].rch:=buildtree(1,k);
q[q[p].rch].f:=p;
pushup(p);
exit;
end;
p:=q[p].rch;
update(p);
while q[p].lch<>null do
begin
p:=q[p].lch;
update(p);
end;
q[p].lch:=buildtree(1,k);
q[q[p].lch].f:=p;
pushup(p);
end;
Procedure move(P:longint);
begin
now:=h;
update(now);
while q[now].s>1 do
begin
if q[q[now].lch].s+1=p then exit;
if p<q[q[now].lch].s+1 then
now:=q[now].lch
else
begin
dec(p,q[q[now].lch].s+1);
now:=q[now].rch;
end;
update(now);
end;
end;
Procedure next;
var
o:node;
begin
update(now);
if q[now].rch<>null then
begin
now:=q[now].rch;
update(now);
while q[now].lch<>null do
begin
now:=q[now].lch;
update(now);
end;
end else
begin
o:=q[now].f;
update(o);
while o<>null do
begin
if q[o].lch=now then break;
o:=q[o].f;
now:=q[now].f;
update(o);
end;
now:=o;
end;
splay(now,null);
end;
Procedure prev;
var
o:node;
begin
update(now);
if q[now].lch<>null then
begin
now:=q[now].lch;
update(now);
while q[now].rch<>null do
begin
now:=q[now].rch;
update(now);
end;
end else
begin
o:=q[now].f;
update(o);
while o<>null do
begin
if q[o].rch=now then break;
o:=q[o].f;
now:=q[now].f;
update(o);
end;
now:=o;
end;
splay(now,null);
end;
Function Getpos:longint;
var
p,qq:node;
begin
p:=q[now].f;
qq:=now;
getpos:=q[q[now].lch].s+1;
// if now=null then error(renone);
update(p);
update(qq);
while p<>null do
begin
if q[p].rch=qq then inc(getpos,q[q[p].lch].s+1);
p:=q[p].f;
qq:=q[qq].f;
update(p);
update(qq);
end;
end;
Procedure get;
var
oldnow:node;
begin
oldnow:=now;
if q[h].s<>getpos then
begin
next;
writeln(q[now].w);
end
else writeln(' ');
now:=oldnow;
splay(now,null);
end;
Procedure delete(P:longint);
var
tmp:node;
begin
tmp:=kth(mmin(q[h].s,getpos+p+1));
splay(now,null);
splay(tmp,h);
update(h);
update(q[h].rch);
update(q[h].lch);
q[q[h].rch].lch:=null;
pushup(q[h].rch);
end;
Procedure ronate(P:longint);
var
tmp:node;
begin
tmp:=kth(mmin(q[h].s,getpos+p+1));
splay(now,null);
splay(tmp,h);
update(q[q[h].rch].lch);
update(q[h].rch);
update(h);
q[q[q[h].rch].lch].ro:=true;
//q[q[h].rch].lch:=null;
end;
Procedure init;
var
p:node;
begin
top:=0;
new(null);
with q[null] do
begin
s:=0;
lch:=null;
rch:=null;
f:=null;
w:=#0;
end;
new(h);now:=h;
with q[h] do
begin
lch:=null;
rch:=null;
f:=null;
w:=#0;
s:=1;
end;
for i:=1 to 10 do
ss[i]:=#0;
insert(10);
end;
Procedure readchar(P:longint);
var
i:longint;
o:char;
begin
for i:=1 to p do
read(o);
end;
begin
{$IFDEF INDEBUG}
fopen;
{$ENDIF}
readln(n);
init;
for i:=1 to n do
begin
read(c);
case c of
'M':
begin
readchar(3);
readln(k);
move(k+1);
end;
'I':
begin
readchar(5);
readln(k);
for j:=1 to k do
read(ss[j]);
readln;
insert(k);
end;
'D':
begin
readchar(5);
readln(k);
delete(k);
end;
'R':
begin
readchar(5);
readln(k);
ronate(k);
end;
'G':
begin
get;
readchar(2);
readln;
end;
'P':
begin
prev;
readchar(3);
readln;
end;
'N':
begin
next;
readchar(3);
readln;
end;
end;
// writeln('No.',i,' Succeed! ');
//flush(output);
//get;
end;
{$IFDEF INDEBUG}
fclose;
{$ENDIF}
end.