CF232E Quick Tortoise , Fzoj 3118

这一题由于数据较多,我们考虑离线处理。

分治。对于两个点s,t,如果起点在mid这条横线上方,终点在下方,那么它必定会穿过mid这条线。所以只要s可以到mid上一点x,x可以到t,st就是安全的。

用bitset维护。设\(f1[i][j]\)为上方ij到mid这条线的是否可以的01值,\(f2[i][j]\)为下方ij到mid的01值。将f1[sx][sy]&f2[tx][ty],如果结果存在1,那么就能走到。

Codeforces版本

#include <cstdio>
#include <bitset>
#include <string>
#include <algorithm>
using namespace std;
const int S=505,N=600003;
int n,m,Q,fr[S],ed[S];
char a[S][S];
bitset<500> f[S][S],g[S][S],h;
bool res[N];
struct info
{
    int x,y,X,Y,i;
}w[N];
void divdo(int l,int r)
{
    if (l>r) return;
    int mid=(l+r)>>1;
    for (int i=m;i>=1;i--)
    {
        if (a[mid][i]=='0')
        {
            f[mid][i]=f[mid][i+1];
            f[mid][i][i]=1;
        }
        else f[mid][i].reset();
    }
    for (int i=mid-1;i>=l;i--)
        for (int j=m;j>=1;j--)
        {
            f[i][j].reset();
            if (a[i][j]=='0')
            {
                if (a[i+1][j]=='0')
                    f[i][j]|=f[i+1][j];
                if (a[i][j+1]=='0')
                    f[i][j]|=f[i][j+1];
            }
        }
        

    for (int i=1;i<=m;i++)
    {
        if (a[mid][i]=='0')
        {
            g[mid][i]=g[mid][i-1];
            g[mid][i][i]=1;
        }
        else g[mid][i].reset();
    }
    for (int i=mid+1;i<=r;i++)
        for (int j=1;j<=m;j++)
        {
            g[i][j].reset();
            if (a[i][j]=='0')
            {
                if (a[i-1][j]=='0')
                    g[i][j]|=g[i-1][j];
                if (a[i][j-1]=='0')
                    g[i][j]|=g[i][j-1];
            }
        }
    for (int i=fr[l];i<=ed[mid];i++)
    {
        if (mid<=w[i].X && w[i].X<=r)
        {
            h=f[w[i].x][w[i].y]&g[w[i].X][w[i].Y];
            if (h.any())
                res[w[i].i]=true;
        }
    }
    divdo(l,mid-1);
    divdo(mid+1,r);
}
void read(int &s)
{
    s=0;char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();
}
inline bool cmp(const info &a,const info &b)
{
    return a.x<b.x;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%s",a[i]+1);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            if (a[i][j]=='.')
                a[i][j]='0';
            else a[i][j]='1';
    scanf("%d",&Q);
    for (int i=1;i<=Q;i++)
    {
        read(w[i].x);
        read(w[i].y);
        read(w[i].X);
        read(w[i].Y);
        w[i].i=i;
    }
    sort(w+1,w+1+Q,cmp);
    int ii=1;
    for (int i=1;i<=n;i++)
    {
        while (ii<=Q && w[ii].x<=i)
            ii++;
        ed[i]=ii-1;
    }
    ii=Q;
    for (int i=n;i>=1;i--)
    {
        while (ii>=1 && w[ii].x>=i)
            ii--;
        fr[i]=ii+1;
    }
    divdo(1,n);
    for (int i=1;i<=Q;i++)
        if (res[i]) puts("Yes");
        else puts("No");
    return 0;
}

Fzoj版本

#include <cstdio>
#include <bitset>
#include <string>
#include <algorithm>
using namespace std;
const int S=505,N=600003;
int n,m,Q,fr[S],ed[S];
char a[S][S];
bitset<500> f[S][S],g[S][S],h;
bool res[N];
struct info
{
    int x,y,X,Y,i;
}w[N];
void divdo(int l,int r)
{
    if (l>r) return;
    int mid=(l+r)>>1;
    for (int i=m;i>=1;i--)
    {
        if (a[mid][i]=='0')
        {
            f[mid][i]=f[mid][i+1];
            f[mid][i][i]=1;
        }
        else f[mid][i].reset();
    }
    for (int i=mid-1;i>=l;i--)
        for (int j=m;j>=1;j--)
        {
            f[i][j].reset();
            if (a[i][j]=='0')
            {
                if (a[i+1][j]=='0')
                    f[i][j]|=f[i+1][j];
                if (a[i][j+1]=='0')
                    f[i][j]|=f[i][j+1];
            }
        }
        

    for (int i=1;i<=m;i++)
    {
        if (a[mid][i]=='0')
        {
            g[mid][i]=g[mid][i-1];
            g[mid][i][i]=1;
        }
        else g[mid][i].reset();
    }
    for (int i=mid+1;i<=r;i++)
        for (int j=1;j<=m;j++)
        {
            g[i][j].reset();
            if (a[i][j]=='0')
            {
                if (a[i-1][j]=='0')
                    g[i][j]|=g[i-1][j];
                if (a[i][j-1]=='0')
                    g[i][j]|=g[i][j-1];
            }
        }
    for (int i=fr[l];i<=ed[mid];i++)
    {
        if (l<=w[i].x && w[i].x<=mid && mid<=w[i].X && w[i].X<=r)
        {
            h=f[w[i].x][w[i].y]&g[w[i].X][w[i].Y];
            if (h.any())
                res[w[i].i]=true;
        }
    }
    divdo(l,mid-1);
    divdo(mid+1,r);
}
void read(int &s)
{
    s=0;char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();
}
inline bool cmp(const info &a,const info &b)
{
    return a.x<b.x;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%s",a[i]+1);
    scanf("%d",&Q);
    for (int i=1;i<=Q;i++)
    {
        read(w[i].x);
        read(w[i].y);
        read(w[i].X);
        read(w[i].Y);
        w[i].i=i;
    }
    sort(w+1,w+1+Q,cmp);
    int ii=1;
    for (int i=1;i<=n;i++)
    {
        while (ii<=Q && w[ii].x<=i)
            ii++;
        ed[i]=ii-1;
    }
    ii=Q;
    for (int i=n;i>=1;i--)
    {
        while (ii>=1 && w[ii].x>=i)
            ii--;
        fr[i]=ii+1;
    }
    divdo(1,n);
    for (int i=1;i<=Q;i++)
        if (res[i]) puts("Safe");
        else puts("Dangerous");
    return 0;
}

转载于:https://www.cnblogs.com/Algebra-hy/p/11121936.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值