您的位置:首页 > 其它

块状链表 poj2887

2011-05-27 11:28 155 查看
相当优秀的数据结构,splay可以做的sequence,它也可以做。

无论是翻转,插入,删除,最大值,最小值,区间和,第k大值,比t小数,第k个数,都可以做

该题只需插入和查询第k个数就可以了。

查询的时候要将长度小的块合并,插入的时候也可以做(但我懒得编了)。

1、查询:判断第x个块长度是否>k,若满足,则在该块第k个,否则k:=k-x.len,查询x.next;在此过程中顺便合并长度之和<sqrt(n)的块。

2、插入:若k>总长则插入在最后块,若块已满,则新建块,last指针后移;否则查询k号位置,若此块未满则直接插入,否则将此块从k处分裂,再插入。分裂的块可能会在之后合并,但短时间内会增加超出预估的块数,所以要多预设一部分块。

move函数很方便,不用担心超时,因为最多移sqrt(n)个,预设块可以开个栈,每次添块就从栈中取,合并块就将其中一个压入栈中。

这道题也可以用逆推的方式用线段树做,好像很少有人想到,思路由罗雨屏提供,详情可参见下一篇博文

const maxl=1000;
type block=record
      len,next:longint;
      s:array[1..1500]of char;
     end;
var a:array[0..4001]of block;
    n,last,he,ans,new,top,head,l:longint;
    st:array[1..500000]of longint;
procedure conect(x,y:longint);
begin
 move(a[y].s[1],a[x].s[a[x].len+1],a[y].len);
 a[x].len:=a[x].len+a[y].len;a[x].next:=a[y].next;
 fillchar(a[y],sizeof(a[y]),0);
 inc(top);st[top]:=y
end;
function find(x:longint):longint;
begin
 he:=head;
 while a[he].len<x do begin
  while a[he].len+a[a[he].next].len<maxl do conect(he,a[he].next);
  if a[he].len>=x then break else x:=x-a[he].len;
  he:=a[he].next
 end;
 find:=x
end;
procedure inset(x:char;k:longint);
var ne:longint;
begin
 inc(l);
 if k>l-1 then begin
  if a[last].len<maxl then begin
   inc(a[last].len);a[last].s[a[last].len]:=x;
   exit
  end;
  inc(new);ne:=st[new];
  a[last].next:=ne;last:=ne;
  inc(a[ne].len);a[ne].s[a[ne].len]:=x;
  exit
 end;
 ans:=find(k);
 if a[he].len<maxl then begin
  with a[he] do begin
   move(s[ans],s[ans+1],len-ans+1);
   s[ans]:=x;inc(len)
  end;
  exit
 end;
 inc(new);ne:=st[new];
 a[ne].next:=a[he].next;a[he].next:=ne;
 move(a[he].s[ans],a[ne].s[1],a[he].len-ans+1);
 a[ne].len:=a[he].len-ans+1;a[he].len:=ans;a[he].s[ans]:=x;
 if last=he then last:=ne
end;
procedure init;
var i,ne:longint;
    x,y,z,p:char;
    k:longint;
begin
 for i:=1 to 4001 do st[i]:=i;top:=4001;
 last:=0;new:=0;a[0].len:=maxl;head:=1;l:=0;
 while not(seekeoln) do begin
  read(x);
  with a[last] do
   if len<maxl-1 then begin
    inc(len);s[len]:=x;inc(l)
   end
   else begin
    inc(new);ne:=st[new];a[last].next:=ne;
    last:=ne;inc(a[ne].len);a[ne].s[a[ne].len]:=x;inc(l)
   end
 end;
 readln;
 readln(n);
 for i:=1 to n do begin
  read(x,y);
  if x='I' then begin
   readln(z,p,k);
   inset(z,k)
  end
  else begin
   readln(k);
   ans:=find(k);
   writeln(a[he].s[ans])
  end
 end
end;
begin
assign(input,'2887.in');reset(input);
 init;
close(input)
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: