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