[AHOI2006]Editor文本编辑器Splay Pascal

http://www.lydsy.com/JudgeOnline/problem.php?id=1269

1269: [AHOI2006]文本编辑器editor
Time Limit: 10 Sec  Memory Limit: 162 MB

Description
这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。 编写一个程序: 建立一个空的文本编辑器。 从输入文件中读入一些操作指令并执行。 对所有执行过的GET操作,将指定的内容写入输出文件。

Input
输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。

Output
依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。

Sample Input
10
Insert 13
Balanced eert
Move 2
Delete 5
Next
Insert 7
editor
Move 0
Get
Move 11
Rotate 4
Get

Sample Output
B
t


HINT

对输入数据我们有如下假定: 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操作不会把光标移动到非法位置。 输入文件没有错误。


Source
鸣谢seter重新制作数据

 裸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.

 

 

转载于:https://www.cnblogs.com/htfy/archive/2012/12/25/2833107.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值