【CF232E】Quick Tortoise

题目

题目链接:https://codeforces.com/problemset/problem/232/E
在一个 \(n \times m\) 的网格上,有一些格子是障碍。给定 \(Q\) 个询问,每次询问是否能只通过向下走和向右走从格子 \((x_1,y_1)\) 走到格子 \((x_2,y_2)\)
\(n,m\leq 500\)\(Q\leq 6\times 10^5\)

思路

简单粗暴的想法就是直接枚举每一行 \(i\),然后对于网格中的所有点处理出一个 bitset 表示能不能到第 \(i\) 行的每一个点。然后枚举询问,如果 \(x_1\leq i\leq x_2\) 的话,判断起点与终点的 bitset 是否有交即可。
这样做是 \(O(\frac{n^2m^2}{\omega}+\frac{Qn}{\omega})\) 的。显然过不了。
但是观察到对于一个询问,只需要找一个在 \([x_1,x_2]\) 中的行来跑就行了。也就是说,按照上述做法处理完第 \(i\) 行后,第 \(i+1\) 行开始就没有必要考虑行不超过 \(i\) 的询问了。
这启发我们采用分治。对于当前区间 \([l,r]\),处理出第 \(mid\) 行的 bitset,然后对于这个区间内的询问,如果没有跨过第 \(mid\) 行,就继续分治下去做;否则判断两个 bitset 是否有交。
时间复杂度 \(O(\frac{n^2m\log n}{\omega}+Q(\log n+\frac{n}{\omega}))\)

代码

#include <bits/stdc++.h>
#define x1 WYCAKIOI
#define x2 WYCAKIOIOI
#define y1 WYCAKIOIOIOI
#define y2 WYCAKIOIOIOIOI
using namespace std;

const int N=510,M=600010;
int n,m,Q;
char s[N][N];
bool ans[M];
bitset<N> f[N][N],g[N][N];

struct node
{
	int x1,y1,x2,y2,id;
};

vector<node> a[N*4];

void solve(int x,int l,int r)
{
	if (l>r) return;
	for (int i=l;i<=r;i++)
		for (int j=1;j<=m;j++)
			f[i][j].reset(),g[i][j].reset();
	int mid=(l+r)>>1;
	for (int i=m;i>=1;i--)
		if (s[mid][i]=='.')
			f[mid][i][i]=1,f[mid][i]|=f[mid][i+1];
	for (int i=1;i<=m;i++)
		if (s[mid][i]=='.')
			g[mid][i][i]=1,g[mid][i]|=g[mid][i-1];
	for (int i=mid-1;i>=l;i--)
		for (int j=m;j>=1;j--)
			if (s[i][j]=='.')
				f[i][j]|=f[i+1][j],f[i][j]|=f[i][j+1];
	for (int i=mid+1;i<=r;i++)
		for (int j=1;j<=m;j++)
			if (s[i][j]=='.')
				g[i][j]|=g[i-1][j],g[i][j]|=g[i][j-1];
	for (int i=0;i<a[x].size();i++)
	{
		if (a[x][i].x2<mid) a[x*2].push_back(a[x][i]);
		if (a[x][i].x1>mid) a[x*2+1].push_back(a[x][i]);
		int x1=a[x][i].x1,y1=a[x][i].y1,x2=a[x][i].x2,y2=a[x][i].y2,id=a[x][i].id;
		ans[id]=((f[x1][y1]&g[x2][y2]).count()>0);
	}
	a[x].clear();
	solve(x*2,l,mid-1); solve(x*2+1,mid+1,r);
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%s",s[i]+1);
	scanf("%d",&Q);
	for (int i=1,x1,y1,x2,y2;i<=Q;i++)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		a[1].push_back((node){x1,y1,x2,y2,i});
	}
	solve(1,1,n);
	for (int i=1;i<=Q;i++)
		ans[i] ? cout<<"Yes\n" : cout<<"No\n";
	return 0;
}
posted @ 2021-08-25 22:05  stoorz  阅读(34)  评论(0编辑  收藏  举报