CF232E Quick Tortoise

本文介绍了如何使用分治策略解决一个关于n×m网格的可达性问题,通过预处理和bitset数据结构优化查询效率,时间复杂度达到O(n^2mlogn/ω + Qlogn)。关键步骤包括离线处理查询、构造f和g矩阵以及利用位运算判断两点间路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://www.luogu.com.cn/problem/CF232E


D e s c r i p t i o n Description Description

给定一个 n × m n\times m n×m的网格,有些格子不能走,每次只能向右或向下走, Q Q Q次询问,每次询问一个点能否到另一个点

数据范围: n , m ≤ 500 , Q ≤ 6 × 1 0 5 n,m\leq 500,Q\leq 6\times 10^5 n,m500,Q6×105


S o l u t i o n Solution Solution

将询问离线后分治,对于一组查询的 x x x位于 [ L , R ] [L,R] [L,R]的询问,若能到达,其必然存在一条路径使得出发点可以到达 ( m i d , i ) (mid,i) (mid,i),然后从 ( m i d , i ) (mid,i) (mid,i)可以到达终点

至此,我们可以用 f i , j , k f_{i,j,k} fi,j,k表示从 ( i , j ) (i,j) (i,j)出发能否到达 ( m i d , k ) (mid,k) (mid,k),用 g i , j , k g_{i,j,k} gi,j,k表示从 ( m i d , k ) (mid,k) (mid,k)出发能否到达 ( i , j ) (i,j) (i,j),对于后者,我们直接倒序转移即可

通过 f [ x ] [ y ] & g [ q x ] [ q y ] f[x][y]\& g[qx][qy] f[x][y]&g[qx][qy]即可得到是否有解

使用 b i t s e t bitset bitset优化后即可通过本题

时间复杂度: O ( n 2 m log ⁡ n ω + Q log ⁡ n ) O(\frac{n^2m\log n}\omega+Q\log n) O(ωn2mlogn+Qlogn)


C o d e Code Code
//#pragma GCC optimize(2)
//%:pragma GCC optimize(3)
//%:pragma GCC optimize("Ofast")
//%:pragma GCC optimize("inline")971955756
#include<cctype>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;int n,m,Q,p,ans[600010];
char s[510][510];
struct node{int x,y,qx,qy,id;}q[600010],t[600010];
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
bitset<501>f[501][501],g[501][501];
inline void solve(int l,int r,int ql,int qr)
{
	if(l>r||ql>qr) return;
	int tl=ql-1,tr=qr+1,mid=l+r>>1;
	for(register int i=1;i<=m;i++) f[mid][i]=g[mid][i]=0;
	for(register int i=m;i;i--) if(s[mid][i]=='.') f[mid][i][i]=1,f[mid][i]|=f[mid][i+1];
	for(register int i=1;i<=m;i++) if(s[mid][i]=='.') g[mid][i][i]=1,g[mid][i]|=g[mid][i-1];
	for(register int i=mid-1;i>=l;i--) for(register int j=m;j;j--) if(s[i][j]=='.') f[i][j]=f[i+1][j]|f[i][j+1];else f[i][j]=0;
	for(register int i=mid+1;i<=r;i++) for(register int j=1;j<=m;j++) if(s[i][j]=='.') g[i][j]=g[i-1][j]|g[i][j-1];else g[i][j]=0;
	for(register int i=ql;i<=qr;i++)
	{
		if(q[i].qx<mid) {t[++tl]=q[i];continue;}
		if(q[i].x>mid) {t[--tr]=q[i];continue;}
		ans[q[i].id]=(f[q[i].x][q[i].y]&g[q[i].qx][q[i].qy]).any();
	}
	for(register int i=ql;i<=tl;i++) q[i]=t[i];
	for(register int i=tr;i<=qr;i++) q[i]=t[i];
	solve(l,mid,ql,tl);solve(mid+1,r,tr,qr);
	return;
	
}
signed main()
{
//	freopen("grid.in","r",stdin);
//	freopen("grid.out","w",stdout);
	n=read();m=read();
	for(register int i=1;i<=n;i++) scanf("%s",s[i]+1);
	Q=read();
	for(register int i=1;i<=Q;i++)
	{
		q[i].x=read();q[i].y=read();
		q[i].qx=read();q[i].qy=read();
		q[i].id=i;
	}
	solve(1,n,1,Q);
	for(register int i=1;i<=Q;i++) puts(ans[i]?"Yes":"No");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值