rq-104

题目描述

传说中,南极有一片广阔的冰原,在冰原下藏有史前文明的遗址。整个冰原被横竖划分成了很多个大小相等的方格。在这个冰原上有N个大小不等的矩形冰山,这些巨大的冰山有着和南极一样古老的历史,每个矩形冰山至少占据一个方格,且其必定完整地占据方格。冰山和冰山之间不会重叠,也不会有边或点相连。以下两种情况均是不可能出现的:
ACM探险队在经过多年准备之后决定在这个冰原上寻找遗址。根据他们掌握的资料,在这个冰原上一个大小为一格的深洞中,藏有一个由史前人类制作的开关。而唯一可以打开这个开关的是一个占据接近一格的可移动的小冰块。显然,在南极是不可能有这样小的独立冰块的,所以这块冰块也一定是史前文明的产物。他们在想办法把这个冰块推到洞里去,这样就可以打开一条通往冰原底部的通道,发掘史前文明的秘密。冰块的起始位置与深洞的位置均不和任何冰山相邻。
这个冰原上的冰面和冰山都是完全光滑的,轻轻的推动冰块就可以使这个冰块向前滑行,直到撞到一座冰山就在它的边上停下来。冰块可以穿过冰面上所有没有冰山的区域,也可以从两座冰山之间穿过(见下图)。冰块只能沿网格方向推动。

请你帮助他们以最少的推动次数将冰块推入深洞中。

输入格式

输入文件第一行为冰山的个数N (1<=N<=4000),第二行为冰块开始所在的方格坐标X1,Y1,第三行为深洞所在的方格坐标X2,Y2,以下N行每行有四个数,分别是每个冰山所占的格子左上角和右下角坐标Xi1,Yi1,Xi2,Yi2

输出格式

输出文件仅包含一个整数,为最少推动冰块的次数。如果无法将冰块推入深洞中,则输出0。

==================================================================

这题的几个题解都说是离散化+宽搜,但我总觉的开一个8000*8000的数组不靠谱(64M啊!)。

我的做法:

这题如果把当中可以停的点当作节点,构图,求个最短路就行了。关键是无法对点进行有效的编号,于是我想到了splay,通过一个query(x,y)函数返回对应点的指针(若该点不在容器中会自动生成一个新的点,把它的dis设成+Inf),这样在spfa的队列中只记下对应点的指针就可以了;刚开始的时候,spfa写成了栈式,tle了,对于这个有特殊性的图来说,栈式是速度最慢的,因为边权都是1,破坏了宽搜的那种最优性,如果写成队列式,搜到终点就可以exit了;由于不好确定队列开多大,我队列写成了链表;还有就是判断停止,我这题用朴素就可以过了,我用二分缩短枚举范围,但效率没高多少,应该还可以用线段树优化,但感觉没想透,所以暂时没用,在跟它类似的APIO-path里加上线段树吧~

================================================

Code:

type
    link=^node;
    node=record pre:link; ch:array[0..1] of link; x,y,dis:longint; end;
    qlink=^qnode;
    qnode=record x:link; next:qlink; end;
    data=record x,low,high:longint; end;
    arr=array[1..4000] of data;
var que,last:qlink;
    root:link;
    n,x1,y1,x2,y2:longint;
//============================================================================//
    arr1,arr2,arr3,arr4:arr;
procedure insert(var a:arr;i,x,low,high:longint);
begin
     a[i].x:=x;
     a[i].low:=low;
     a[i].high:=high;
end;
procedure sort(var a:arr;l,r:longint);
var i,j:longint; mid,tmp:data;
begin
     i:=l; j:=r; mid:=a[(l+r)shr 1];
     repeat
           while (a[i].x<mid.x)do inc(i);
           while (a[j].x>mid.x)do dec(j);
           if i<=j then begin
              tmp:=a[i]; a[i]:=a[j]; a[j]:=tmp;
              inc(i); dec(j);
           end;
     until i>j;
     if i<r then sort(a,i,r);
     if l<j then sort(a,l,j);
end;
function up(x,y:longint;var tx:longint):boolean;{arr1}
var l,r,i,mid:longint;
begin
     l:=1; r:=n;
     while l<r do begin
           mid:=(l+r)shr 1+1;
           if arr1[mid].x<x then l:=mid
           else r:=mid-1;
     end;
     tx:=-maxlongint;
     for i:=l downto 1 do
     if (arr1[i].x<x)and(arr1[i].low<=y)and(arr1[i].high>=y)then begin
        tx:=arr1[i].x+1;
        break;
     end;
     if (y=y2)and(x2>=tx)and(x2<=x)then tx:=x2;
     if (tx=-maxlongint)or(tx=x)then exit(false) else exit(true);
end;
function down(x,y:longint;var tx:longint):boolean;{arr2}
var l,r,i,mid:longint;
begin
     l:=1; r:=n;
     while l<r do begin
           mid:=(l+r)shr 1;
           if arr2[mid].x>x then r:=mid
           else l:=mid+1;
     end;
     tx:=maxlongint;
     for i:=r to n do
     if (arr2[i].x>x)and(arr2[i].low<=y)and(arr2[i].high>=y)then begin
        tx:=arr2[i].x-1;
        break;
     end;
     if (y=y2)and(x2<=tx)and(x2>=x)then tx:=x2;
     if (tx=maxlongint)or(tx=x)then exit(false) else exit(true);
end;
function left(x,y:longint;var ty:longint):boolean;{arr4}
var l,r,i,mid:longint;
begin
     l:=1; r:=n;
     while l<r do begin
           mid:=(l+r)shr 1+1;
           if arr4[mid].x<y then l:=mid
           else r:=mid-1;
     end;
     ty:=-maxlongint;
     for i:=l downto 1 do
     if (arr4[i].x<y)and(arr4[i].low<=x)and(arr4[i].high>=x)then begin
        ty:=arr4[i].x+1;
        break;
     end;
     if (x=x2)and(y2>=ty)and(y2<=y) then ty:=y2;
     if (ty=-maxlongint)or(ty=y)then exit(false) else exit(true);
end;
function right(x,y:longint;var ty:longint):boolean;{arr3}
var l,r,i,mid:longint;
begin
     l:=1; r:=n;
     while l<r do begin
           mid:=(l+r)shr 1;
           if arr3[mid].x>y then r:=mid
           else l:=mid+1;
     end;
     ty:=maxlongint;
     for i:=r to n do
     if (arr3[i].x>y)and(arr3[i].low<=x)and(arr3[i].high>=x)then begin
        ty:=arr3[i].x-1;
        break;
     end;
     if (x=x2)and(y2>=y)and(y2<=ty)then ty:=y2;
     if (ty=maxlongint)or(ty=y)then exit(false)else exit(true);
end;
//============================================================================//
procedure rotate(x:link;k:longint);
var f:link;
begin
     f:=x^.pre;
     f^.ch[1-k]:=x^.ch[k]; if x^.ch[k]<>nil then x^.ch[k]^.pre:=f;
     x^.pre:=f^.pre; if f^.pre<>nil then if f^.pre^.ch[0]=f then f^.pre^.ch[0]:=x else f^.pre^.ch[1]:=x;
     x^.ch[k]:=f; f^.pre:=x; if f=root then root:=x;
end;
procedure splay(x,goal:link);
var y,z:link;
begin
     while x^.pre<>goal do
           if x^.pre^.pre=goal then
              if x^.pre^.ch[0]=x then rotate(x,1)
              else rotate(x,0)
           else begin
                y:=x^.pre; z:=y^.pre;
                if z^.ch[0]=y then
                   if y^.ch[0]=x then begin rotate(y,1); rotate(x,1); end
                   else begin rotate(x,0); rotate(x,1); end
                else if y^.ch[1]=x then begin rotate(y,0); rotate(x,0); end
                     else begin rotate(x,1); rotate(x,0); end;
           end;
end;
function query(x,y:longint):link;
         procedure search(var r:link);
         begin
              if r=nil then begin
                 new(r);
                 r^.x:=x;
                 r^.y:=y;
                 r^.dis:=maxlongint;
                 r^.ch[0]:=nil;
                 r^.ch[1]:=nil;
                 query:=r;
              end else if r^.x<x then begin search(r^.ch[1]); r^.ch[1]^.pre:=r; end
              else if r^.x>x then begin search(r^.ch[0]); r^.ch[0]^.pre:=r; end
              else if r^.y<y then begin search(r^.ch[1]); r^.ch[1]^.pre:=r; end
              else if r^.y>y then begin search(r^.ch[0]); r^.ch[0]^.pre:=r; end
              else query:=r;
         end;
begin
     search(root);
     root^.pre:=nil;
     splay(query,nil);
end;
//============================================================================//
procedure push(x:link);
var p:qlink;
begin
     new(p);
     p^.x:=x;
     p^.next:=nil;
     if que=nil then begin
        que:=p;
        last:=p;
     end else begin
         last^.next:=p;
         last:=p;
     end;
end;
function pop:link;
begin
     pop:=que^.x;
     que:=que^.next;
end;
//============================================================================//
function spfa:longint;
var t:longint; p,q:link;
begin
     que:=nil;
     root:=nil;
     q:=query(x1,y1);
     q^.dis:=0;
     push(q);
     while que<>nil do begin
       q:=pop;
       with q^ do begin
            if (x=x2)and(y=y2)then exit(dis);
           if up(x,y,t) then begin
              p:=query(t,y);
              if p^.dis>dis+1 then begin
                 p^.dis:=dis+1;
                 push(p);
              end;
           end;
           if down(x,y,t) then begin
              p:=query(t,y);
              if p^.dis>dis+1 then begin
                 p^.dis:=dis+1;
                 push(p);
              end;
           end;
           if left(x,y,t) then begin
              p:=query(x,t);
              if p^.dis>dis+1 then begin
                 p^.dis:=dis+1;
                 push(p);
              end;
           end;
           if right(x,y,t) then begin
              p:=query(x,t);
              if p^.dis>dis+1 then begin
                 p^.dis:=dis+1;
                 push(p);
              end;
           end;
       end;
     end;
     q:=query(x2,y2);
     if q^.dis=maxlongint then exit(0)
     else exit(q^.dis);
end;
//
procedure main;
var i,tx1,tx2,ty1,ty2:longint;
begin
     readln(n);
     readln(x1,y1);
     readln(x2,y2);
     for i:=1 to n do begin
         readln(tx1,ty1,tx2,ty2);
         insert(arr1,i,tx2,ty1,ty2);
         insert(arr2,i,tx1,ty1,ty2);
         insert(arr3,i,ty1,tx1,tx2);
         insert(arr4,i,ty2,tx1,tx2);
     end;
     sort(arr1,1,n);
     sort(arr2,1,n);
     sort(arr3,1,n);
     sort(arr4,1,n);
     write(spfa);
end;
begin
     main;
end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值