zoukankan      html  css  js  c++  java
  • jzoj100048. 紧急撤离

    Description

    某日, 敌军对某村落展开攻击,所幸我情报部门提前预知了消息,村民兵武装连夜组织村民快速转移,为此他们需要赶往地道入口。已知村庄形成了 N * M 的方格网络,周围被封锁,无法穿行。其中有些方格没有敌军占领,可以进入,有些方格已经被敌军渗透,不能进入。由于敌军的步步紧逼,民众只能向行或列增大的地方移动:即(x, y) → (x + 1, y)或(x, y) → (x, y + 1)。 机智的 Star 手提笔记本,正和民兵队长商议对策。民兵队长会问你 Q 个问 题,每个问题均类似于坐标(a, b)的村民能否安全到达位于坐标(c, d)的地道(队长是机智的,他的问题总保证起点和终点均安全),你需要赶快写出程序来帮助他。

    Input

    第 1 行两个整数 N, M;
    第 2 ~ n + 1 行给出一个 N * M 的 0/1 矩形(每行可看作一字符串),其中 0 表示安全,1 表示不安全,设第 i + 1 行第 j 列的位置坐标为(i, j)。
    第 n + 2 行一个整数 Q;
    接下来 Q 行每行四个整数 a、b、c、d,保证坐标合法。

    Output

    对于每组询问,输出一行“Safe”或“Dangerous”。

    Sample Input

    7 7
    0100000
    0000010
    0001010
    0011000
    1000010
    0000000
    0111001
    5
    3 3 4 6
    6 1 6 7
    4 5 6 5
    3 3 4 5
    4 6 7 6

    Sample Output

    Dangerous
    Safe
    Safe
    Dangerous
    Dangerous

    Data Constraint

    对于 30%的数据,n, m ≤ 50;
    对于另外 20%的数据,n, m ≤ 200、q ≤ 1000;
    对于 100%的数据,n, m ≤ 500、q ≤ 600000。

    题解

    此题为坑题。
    坑在何处?卡你常数。
    首先,这题我们发现,一个点每次只能从某个点依次往下或往右走,走到结束点。
    那么直观的想法——求出两两点之间最短路径,然后O(1)判断即可。
    然而这种方法只可以过30分。
    那么再想想,发现另外20分很好弄,于是可以暴力得到50分的好成绩。
    可是100分呢?
    由于求两两点之间的最短路,那么就用到的是弗洛伊德。
    弗洛伊德有一个中转点,那么我们就可以考虑从起点到中转点再到终点看看可否行得通。
    那么就有一个直观的想法——分治。
    我们考虑500*500中,从列里面分治,枚举中间列,然后找出从中间穿过的询问,DP求出状态即可。
    一步一步来看——
    首先枚举中间列,就是每次分治下去,不用讲了吧。
    其次是找出从中间穿过的询问。
    我们考虑先把询问都按照起点的y坐标从小到大排序,然后,建一个双向链表,做过的询问就从链表中删掉。
    可以优化时间——O(qlogn)O(q log n)
    当然,如果快排太慢,可以考虑桶排。
    最后是DP。
    我们设一个f[i,j]表示从中间的列右边的某个点反向走能够走到中间列状态,一个g示从中间的列左边的某个点正向走能够走到中间列状态
    这个状态是二进制的,虽说有25002^{500}但是我们可以考虑压位,当然,C++可以用bitset。
    O(n3logn/ω)O(n^3*log n/ omega)
    具体时间很简单,只是时间可能卡的紧些。

    代码

    {$inline on}
    uses math;
    type
            new=record
                    x,y:longint;
            end;
            new1=array of longint;
    var
            i,j,k,l,n,m,q,answer,up:longint;
            map:array[1..500,1..500] of boolean;
            wz:array[1..500,1..500] of new;
            x1,y1,x2,y2,id,da:array[1..600000] of longint;
            xx1,yy1,xx2,yy2,idd:array[1..600000] of longint;
            ans:array[1..600000] of longint;
            s:ansistring;
            f,g:array[1..500,1..500,0..9] of int64;
            mi:array[0..60] of int64;
            wz1,wz2:array[1..500] of longint;
            t:array[1..500] of new1;
            next,last:array[0..600000] of longint;
            z:array[0..600000] of longint;{
    procedure bfs(i,j,mbx,mby:longint);
    var
            k,l,x,y,nx,ny,head,tail,took:longint;
    begin
            head:=1;
            tail:=1;
            took:=1;
            ans[1]:=0;
            repeat
                    for k:=head to tail do
                    begin
                            for l:=1 to 2 do
                            begin
                                    begin
                                            if map[nx,ny] then
                                            begin
                                            end;
                                    end;
                            end;
                    end;
                    head:=tail+1;
                    tail:=took;
            until head>tail;
    end;
    procedure gc;inline;
    var
            i,j:longint;
    begin
            for i:=1 to n do
            begin
                    for j:=1 to m do
                    begin
                            bfs(i,j,0,0);
                    end;
            end;
    end;}
    procedure tsort;inline;
    var
            i,j,k:longint;
    begin
            for i:=1 to 500 do
            begin
                    setlength(t[i],1);
                    t[i,0]:=0;
            end;
            for i:=1 to q do
            begin
                    setlength(t[y1[i]],t[y1[i],0]+2);
                    inc(t[y1[i],0]);
                    t[y1[i],t[y1[i],0]]:=i;
            end;
            k:=0;
            for i:=1 to 500 do
            begin
                    for j:=1 to t[i,0] do
                    begin
                            inc(k);
                            xx1[k]:=x1[t[i,j]];
                            yy1[k]:=y1[t[i,j]];
                            xx2[k]:=x2[t[i,j]];
                            yy2[k]:=y2[t[i,j]];
                            idd[k]:=id[t[i,j]];
                    end;
            end;
            for i:=1 to k do
            begin
                    x1[i]:=xx1[i];y1[i]:=yy1[i];x2[i]:=xx2[i];y2[i]:=yy2[i];id[i]:=idd[i];
            end;
    end;
    procedure daan(l,r:longint);inline;
    var
            i,j,k,min1,max1,min2,max2,mid:longint;
    begin
            if l>r then exit;
            mid:=(l+r) div 2;
            z[0]:=0;
            min1:=maxlongint;
            max1:=0;
            min2:=maxlongint;
            max2:=0;
            i:=next[0];
            while i<=q do
            begin
                    if (y1[i]>=l)and(y1[i]<=mid)and(y2[i]>=mid)and(y2[i]<=r) then
                    begin
                            min1:=min(min1,y1[i]);
                            max1:=max(max1,y2[i]);
                            min2:=min(min2,x1[i]);
                            max2:=max(max2,x2[i]);
                            inc(z[0]);
                            z[z[0]]:=i;
                            last[next[i]]:=last[i];
                            next[last[i]]:=next[i];
                    end;
                    i:=next[i];
                    if (i=0) or (y1[i]>mid) then break;
            end;
            if z[0]=0 then
            begin
                    daan(l,mid-1);
                    daan(mid+1,r);
            end
            else
            begin
                    for i:=1 to 500 do
                    begin
                            for j:=min1 to max1 do
                            begin
                                    fillchar(f[i,j],sizeof(f[i,j]),0);
                                    fillchar(g[i,j],sizeof(g[i,j]),0);
                            end;
                    end;
                    if (map[1,mid]) then f[1,mid,wz2[1]]:=f[1,mid,wz2[1]] or mi[wz1[1]];
                    if (map[n,mid]) then g[n,mid,wz2[n]]:=g[n,mid,wz2[n]] or mi[wz1[n]];
                    for i:=2 to max2 do
                    begin
                            if map[i,mid] then
                            begin
                                    if map[i-1,mid] then f[i,mid]:=f[i-1,mid];
                                    f[i,mid,wz2[i]]:=f[i,mid,wz2[i]] or mi[wz1[i]];
                            end;
                    end;
                    for i:=n-1 downto min2 do
                    begin
                            if map[i,mid] then
                            begin
                                    if map[i+1,mid] then g[i,mid]:=g[i+1,mid];
                                    g[i,mid,wz2[i]]:=g[i,mid,wz2[i]] or mi[wz1[i]];
                            end;
                    end;
                    for i:=mid+1 to max1 do
                    begin
                            if map[1,i-1] then
                            begin
                                    for k:=1 to up do
                                    begin
                                            f[1,i,k]:=f[1,i,k] or f[1,i-1,k];
                                    end;
                            end;
                            for j:=2 to max2 do
                            begin
                                    if map[j,i] then
                                    begin
                                            if map[j-1,i] then f[j,i]:=f[j-1,i];
                                            if map[j,i-1] then
                                            begin
                                                    for k:=1 to up do
                                                    begin
                                                            f[j,i,k]:=f[j,i,k] or f[j,i-1,k];
                                                    end;
                                            end;
                                    end;
                            end;
                    end;
                    for i:=mid-1 downto min1 do
                    begin
                            if map[n,i+1] then
                            begin
                                    for k:=1 to up do
                                    begin
                                            g[n,i,k]:=g[n,i,k] or g[n,i+1,k];
                                    end;
                            end;
                            for j:=n-1 downto min2 do
                            begin
                                    if map[j,i] then
                                    begin
                                            if map[j+1,i] then g[j,i]:=g[j+1,i];
                                            if map[j,i+1] then
                                            begin
                                                    for k:=1 to up do
                                                    begin
                                                            g[j,i,k]:=g[j,i,k] or g[j,i+1,k];
                                                    end;
                                            end;
                                    end;
                            end;
                    end;
                    for i:=1 to z[0] do
                    begin
                            j:=z[i];
                            for k:=1 to up do
                            begin
                                    if g[x1[j],y1[j],k] and f[x2[j],y2[j],k]>0 then
                                    begin
                                            ans[id[j]]:=1;
                                            break;
                                    end;
                            end;
                            if ans[id[j]]=0 then ans[id[j]]:=-1;
                    end;
                    daan(l,mid-1);
                    daan(mid+1,r);
            end;
    end;
    begin
            //assign(input,'0data.in');reset(input);
            //assign(output,'0data.out');rewrite(output);
            readln(n,m);
            up:=n div 60;
            if n mod 60>0 then inc(up);
            mi[0]:=1;
            for i:=1 to 60 do mi[i]:=mi[i-1]*2;
            for i:=1 to n do
            begin
                    wz1[i]:=(i-1) mod 60;
                    wz2[i]:=i div 60+1;
            end;
            for i:=1 to n do
            begin
                    readln(s);
                    for j:=1 to m do
                    begin
                            if s[j]='0' then map[i,j]:=true
                            else map[i,j]:=false;
                    end;
            end;
            readln(q);
            for i:=1 to q do
            begin
                    read(x1[i],y1[i],x2[i],y2[i]);
                    id[i]:=i;
            end;
            tsort;
            next[0]:=1;
            next[q]:=q+1;
            for i:=2 to q do
            begin
                    next[i-1]:=i;
                    last[i]:=i-1;
            end;
            daan(1,m);
            for i:=1 to q do
            begin
                    if ans[i]=1 then writeln('Safe');
                    if ans[i]=-1 then writeln('Dangerous');
            end;
    end.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    Timed Code
    jQuery的deferred对象详解
    ASP.NET MVC 使用Redis共享Session
    .NET垃圾回收(GC)原理
    强命名程序集,签名,延迟签名
    CLR 关于强命名程序集 .
    .NET程序集强命名删除与再签名技术 源代码剖析
    应用Strong Name保存.NET应用程序集
    使用强命名程序集防范篡改
    1.浅谈CLR
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148378.html
Copyright © 2011-2022 走看看