题目:BZOJ5138.
题目大意:给定一张
n
∗
m
n*m
n∗m的有障碍点的网格,分别有两个位置有人和箱子.现在给出
q
q
q个询问,每次询问从初始状态是否让人把箱子推到某个位置.
1
≤
n
,
m
≤
1.5
∗
1
0
3
,
1
≤
q
≤
5
∗
1
0
4
1\leq n,m\leq 1.5*10^3,1\leq q\leq 5*10^4
1≤n,m≤1.5∗103,1≤q≤5∗104.
看到这道题我们可以想到用bfs来求出一个数组 v i s [ x ] [ y ] [ k ] vis[x][y][k] vis[x][y][k]表示箱子在 ( x , y ) (x,y) (x,y)且人在箱子的 0 / 1 / 2 / 3 0/1/2/3 0/1/2/3方向的状态是否可能到达,但是在箱子位置确定时人还需要用一个bfs来求出是否可以从某个方向到另一个方向,需要 O ( n 2 m 2 ) O(n^2m^2) O(n2m2)才可以实现.
但是仔细考虑一下,会发现若要从 ( x , y ) (x,y) (x,y)的某个方向到另一个方向,原来没有箱子时必然有只有一条需要经过 ( x , y ) (x,y) (x,y)的路径.而现在 ( x , y ) (x,y) (x,y)被堵上了,相当于需要在 ( x , y ) (x,y) (x,y)没被堵上时有两条路径,这个问题抽象到图上就是需要这两个方向所在的点在同一个点双连通分量内.
到这一步后,我们可以考虑用一个圆方树来维护这个问题,两个点在同一个点双内只有可能时这两个点在圆方树上有相同的父亲或某个点是另一个点的爷爷,构造出圆方树上的父亲指针即可.
时间复杂度 O ( n m ) O(nm) O(nm).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1500;
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
char s[N+9];
int n,m,cq,b[N+9][N+9];
int px,py,bx,by,vis[N+9][N+9][5];
struct state{
int x,y,g;
state(int X=0,int Y=0,int G=0){x=X;y=Y;g=G;}
};
queue<state>q;
bool Out_map(int x,int y){return x<1||x>n||y<1||y>m;}
void Bfs_vis4(int stx,int sty){
vis[stx][sty][4]=1;q.push(state(stx,sty));
while (!q.empty()){
state t=q.front();q.pop();
for (int i=0;i<4;++i){
int nx=t.x+dx[i],ny=t.y+dy[i];
if (Out_map(nx,ny)||!b[nx][ny]||vis[nx][ny][4]) continue;
vis[nx][ny][4]=1;q.push(state(nx,ny));
}
}
}
struct side{
int y,next;
}e[N*N*8+9];
int lin[N*N+9],cs;
int H(int x,int y){return (x-1)*m+y;}
void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}
void Get_graph(){
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
for (int k=0;k<2;++k){
if (!b[i][j]) continue;
int nx=i+dx[k<<1],ny=j+dy[k<<1];
if (Out_map(nx,ny)||!b[nx][ny]) continue;
Ins2(H(i,j),H(nx,ny));
}
}
int dfn[N*N+9],low[N*N+9],co;
stack<int>sta;
int cn,fa[N*N*2+9];
void Tarjan(int k){
dfn[k]=low[k]=++co;
int flag=0;
sta.push(k);
for (int i=lin[k];i;i=e[i].next)
if (!dfn[e[i].y]){
Tarjan(e[i].y);
if (low[e[i].y]>=dfn[k]){
++flag;
fa[++cn]=k;
while (2333){
int t=sta.top();sta.pop();
fa[t]=cn;
if (t==e[i].y) break;
}
}
low[k]=min(low[k],low[e[i].y]);
}else low[k]=min(low[k],dfn[e[i].y]);
}
void Build(){
cn=n*m;
for (int i=1;i<=n*m;++i)
if (!dfn[i]) Tarjan(i);
}
void Bfs_vis0123(int stx,int sty,int stg){
vis[stx][sty][stg]=1;q.push(state(stx,sty,stg));
while (!q.empty()){
state t=q.front();q.pop();
int nx=t.x+dx[t.g],ny=t.y+dy[t.g];
if (!Out_map(nx,ny)&&b[nx][ny]&&!vis[nx][ny][t.g])
vis[nx][ny][t.g]=1,q.push(state(nx,ny,t.g));
for (int i=0;i<4;++i){
if (vis[t.x][t.y][i]) continue;
nx=t.x-dx[i],ny=t.y-dy[i];
if (Out_map(nx,ny)) continue;
int x=H(t.x-dx[t.g],t.y-dy[t.g]),y=H(nx,ny);
if (fa[x]^fa[y]&&fa[fa[x]]^y&&fa[fa[y]]^x) continue;
vis[t.x][t.y][i]=1,q.push(state(t.x,t.y,i));
}
}
}
Abigail into(){
scanf("%d%d%d",&n,&m,&cq);
for (int i=1;i<=n;++i){
scanf("%s",s+1);
for (int j=1;j<=m;++j)
switch (s[j]){
case '#':
b[i][j]=0;
break;
case '.':
b[i][j]=1;
break;
case 'A':
b[i][j]=1;
px=i;py=j;
break;
case 'B':
b[i][j]=1;
bx=i;by=j;
break;
}
}
}
Abigail work(){
b[bx][by]=0;
Bfs_vis4(px,py);
b[bx][by]=1;
for (int i=0;i<4;++i)
if (vis[bx-dx[i]][by-dy[i]][4]) vis[bx][by][i]=1;
Get_graph();
Build();
for (int i=0;i<4;++i)
if (vis[bx][by][i]) Bfs_vis0123(bx,by,i);
}
Abigail getans(){
for (int i=1;i<=cq;++i){
int x,y;
scanf("%d%d",&x,&y);
puts(vis[x][y][0]||vis[x][y][1]||vis[x][y][2]||vis[x][y][3]||bx==x&&by==y?"YES":"NO");
}
}
int main(){
into();
work();
getans();
return 0;
}