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.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章