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;
}