经典(?)的推箱子问题。
考虑记录 (箱子的位置, bessie 的位置) 这样的二元组当作状态,正确性肯定是可以的。但是状态是 \((nm)^2\) 这就不好了。但是容易观察到只有当箱子和 bessie 挨在一起的时候的状态才是我们需要关心的关键状态,因为这样才能推得动箱子。你 bessie 要是把箱子放着不动,自己到处游走,那谁管你去了那些景点旅游啊。
接下来要做的事情就是给这 \(4nm\) 个状态之间连边,把它们的连通性确定下来。初始状态显然最多只有 \(4\) 种,对结束位置显然也只有最多 \(4\) 种状态,最终这 \(16\) 对中至少一组连通,那答案就是 YES
否则是 NO
。
状态之间的连边只有两种:一种是往当前方向推一格,一种是 bessie 换个方位。前者比较简单,就看看前方有没有障碍物就行了(连的是有向边啊!)。后者的话,判的就是在原图基础上,把箱子的位置堵住(其实就是割掉这个点)然后两种 bessie 的位置是否连通。那这就是圆方树的拿手好戏了——因为把某个点割掉之后原图的分裂情况跟圆方树一致。我们只需要找出 \(4\) 种位置各在哪个儿子树里(或者是割掉的点的子树的补集),枚举一下然后用子树的时间戳区间判就可以了。复杂度是均摊的,不用担心,虽然常数有点大但常数瓶颈不在这里。
上面的后者连边中,并不是 \(4\) 种情况的每一对连通对都要连双向边,如果这样的话最多要连 \(2\dbinom{4}{2}=12\) 条边,平均每个点连出 \(3\) 条。其实可以找到每个连通类,然后用一个有向环连起来,这样每个点连出 \(1\) 条。不难发现结合前者和后者一共要连 \(8nm\) 条边,这大概到了 1e7 级别。而我个人不太喜欢链式前向星那东西,这题一开始也就用 vector
写了。那么被卡空间、卡时间无疑了。把 vector
换成链式前向星立刻就过了,而且跑得很快,使用空间也只有 ML 的一半——STL,尤其是 vector
deque
之流,确实是奢侈品。下次要是再在有卡空、卡时风险的图论题里不果断用链式前向星,我就 dlxt 好吧!!(把 vector
换成前向星真的很麻烦,还不如一开始就写)
另外这题有个小坑。如果目的地就是箱子本来在的地方的话,你 bessie 甚至不需要能到达箱子周围。
code(其实 u1s1 链式前向星写的挺清爽的)
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=1510;
int n,m,qu;
char a[N][N];
int id(int x,int y){return (x-1)*m+y;}
struct addedge_nei{
int sz,head[N*N],nxt[4*N*N],val[4*N*N];
addedge_nei(){sz=0,memset(head,0,sizeof(head));}
void ae(int x,int y){
sz++,nxt[sz]=head[x],head[x]=sz,val[sz]=y;
}
}nei;
int dfn[2*N*N],low[N*N],nowdfn;
int stk[N*N],top;
int cnt;
struct addedge_cnei{
int sz,head[2*N*N],nxt[4*N*N],val[4*N*N];
addedge_cnei(){sz=0,memset(head,0,sizeof(head));}
void ae(int x,int y){
sz++,nxt[sz]=head[x],head[x]=sz,val[sz]=y;
}
}cnei;
void tar(int x,int fa=0){
stk[top++]=x;
dfn[x]=low[x]=++nowdfn;
if(!fa&&nei.head[x]==0)return cnt++,cnei.ae(n*m+cnt,x),cnei.ae(x,n*m+cnt),void();
for(int i=nei.head[x];i;i=nei.nxt[i]){
int y=nei.val[i];
if(y==fa){fa=-1;continue;}
if(!dfn[y]){
tar(y,x),low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y]){
cnt++;
while(true){
int z=stk[--top];
cnei.ae(n*m+cnt,z),cnei.ae(z,n*m+cnt);
if(z==y)break;
}
cnei.ae(n*m+cnt,x),cnei.ae(x,n*m+cnt);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int mxdfn[2*N*N];
void dfs(int x,int fa=0){
dfn[x]=mxdfn[x]=++nowdfn;
for(int i=cnei.head[x];i;i=cnei.nxt[i]){
int y=cnei.val[i];
if(y==fa)continue;
dfs(y,x);
mxdfn[x]=mxdfn[y];
}
}
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
const string str[]={"right","down","left","up"};
int id0(int x,int y){return x*4-y;}
struct addedge_nei0{
int sz,head[4*N*N],nxt[8*N*N],val[8*N*N];
addedge_nei0(){sz=0,memset(head,0,sizeof(head));}
void ae(int x,int y){
sz++,nxt[sz]=head[x],head[x]=sz,val[sz]=y;
}
}nei0;
bool vis0[4*N*N];
void dfs1(int x){
vis0[x]=true;
for(int i=nei0.head[x];i;i=nei0.nxt[i]){
int y=nei0.val[i];
if(!vis0[y])dfs1(y);
}
}
bool ok(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m&&a[x][y]!=‘#‘;}
bool vis[N*N];
void dfs0(int x,int ban){
vis[x]=true;
for(int i=nei.head[x];i;i=nei.nxt[i]){
int y=nei.val[i];
if(!vis[y]&&y!=ban)dfs0(y,ban);
}
}
int main(){
cin>>n>>m>>qu;
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]!=‘#‘){
if(i<n&&a[i+1][j]!=‘#‘)nei.ae(id(i,j),id(i+1,j)),nei.ae(id(i+1,j),id(i,j));
if(j<m&&a[i][j+1]!=‘#‘)nei.ae(id(i,j),id(i,j+1)),nei.ae(id(i,j+1),id(i,j));
}
for(int i=1;i<=n*m;i++)if(!dfn[i])tar(i);
memset(dfn,0,sizeof(dfn));nowdfn=0;
for(int i=1;i<=n*m;i++)if(!dfn[i])dfs(i);
int A,B;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
if(a[i][j]==‘A‘)A=id(i,j);
if(a[i][j]==‘B‘)B=id(i,j);
}
dfs0(A,B);
vector<int> init;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]!=‘#‘){
int x=id(i,j),in[4]={};
for(int k=0;k<4;k++){
int xn=i+dx[k],yn=j+dy[k];
if(!ok(xn,yn)){in[k]=-1;continue;}
if(x==B&&vis[id(xn,yn)])init.pb(id0(x,k));
int now=0;
for(int o=cnei.head[x];o;o=cnei.nxt[o]){
now++;
int y=cnei.val[o];
if(dfn[y]<dfn[x])continue;
if(dfn[y]<=dfn[id(xn,yn)]&&dfn[id(xn,yn)]<=mxdfn[y])in[k]=now;
}
int xx=i-dx[k],yy=j-dy[k];
if(!ok(xx,yy))continue;
nei0.ae(id0(x,k),id0(id(xx,yy),k));
}
for(int k=0;k<10;k++){
vector<int> v;
for(int o=0;o<4;o++)if(in[o]==k)v.pb(id0(x,o));
for(int o=0;o+1<v.size();o++)nei0.ae(v[o],v[o+1]);
if(v.size()>1)nei0.ae(v.back(),v[0]);
}
}
for(int i=0;i<init.size();i++)dfs1(init[i]);
while(qu--){
int x,y;
scanf("%d%d",&x,&y);
bool yes=id(x,y)==B;
for(int i=0;i<4;i++)yes|=vis0[id0(id(x,y),i)];
puts(yes?"YES":"NO");
}
return 0;
}