题目描述:

bz

luogu

题解:

暴力可以记录$AB$位置转移,这个时候状态是$n^4$的,无法接受。

考虑只记录$A$在$B$旁边时的状态,这个时候状态时$n^2$的。

所以说转移有两种,一种是$A$推$B$一下,另一种是$A$绕到$B$另一侧。

第一种转移显然$O(1)$,瓶颈在第二种。

发现这对点满足点双,所以建出广义圆方树,判两个点是否同父亲或一个点是另一个点的爷爷。

时间复杂度$O(n^2)$。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = ;
template<typename T>
inline void read(T&x)
{
T f = ,c = ;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){c=c*+ch-'';ch=getchar();}
x = f*c;
}
int n,m,Q,nam[N][N],tot,rtx,rty,rt,stx,sty,st,hed[N*N],cnt=;
char mp[N][N];
bool check(int x,int y){return x&&y&&x<=n&&y<=m;}
int dx[]={-,,,},dy[]={,,-,};
struct EG
{
int to,nxt;
}e[*N*N];
void ae(int f,int t)
{
e[++cnt].to = t;
e[cnt].nxt = hed[f];
hed[f] = cnt;
}
int dfn[N*N],low[N*N],tim,fa[N*N*];
int sta[N*N*],tl;
void tarjan(int u,int f)
{
dfn[u] = low[u] = ++tim;
sta[++tl] = u;
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==f)continue;
if(!dfn[to])
{
tarjan(to,u);
low[u] = min(low[u],low[to]);
if(low[to]>=dfn[u])
{
int now = ++tot;
fa[now] = u;
int c = -;
while(c!=to)
{
c = sta[tl--];
fa[c] = now;
}
}
}else low[u] = min(low[u],dfn[to]);
}
}
bool ck(int u,int v)
{
if(fa[u]==fa[v])return ;
if(fa[fa[v]]==u)return ;
if(fa[fa[u]]==v)return ;
return ;
}
bool dp[N][N][];
bool vis[N][N];
struct Pair
{
int x,y;
Pair(){}
Pair(int x,int y):x(x),y(y){}
};
void bfs()
{
queue<Pair>q;
q.push(Pair(rtx,rty));
vis[rtx][rty] = ;
while(!q.empty())
{
Pair tp = q.front();q.pop();
int x = tp.x,y = tp.y;
for(int k=;k<;k++)
{
int xx = x+dx[k],yy = y+dy[k];
if(!nam[xx][yy])continue;
if(xx==stx&&yy==sty)dp[stx][sty][k]=;
else if(!vis[xx][yy])vis[xx][yy]=,q.push(Pair(xx,yy));
}
}
}
struct Tri
{
int x,y,z;
Tri(){}
Tri(int x,int y,int z):x(x),y(y),z(z){}
};
void sol()
{
queue<Tri>q;
for(int k=;k<;k++)if(dp[stx][sty][k])
q.push(Tri(stx,sty,k));
while(!q.empty())
{
Tri tp = q.front();
q.pop();
int x = tp.x,y = tp.y,k = tp.z;
if(nam[x+dx[k]][y+dy[k]]&&!dp[x+dx[k]][y+dy[k]][k])dp[x+dx[k]][y+dy[k]][k]=,q.push(Tri(x+dx[k],y+dy[k],k));
for(int i=;i<;i++)if(nam[x-dx[i]][y-dy[i]]&&i!=k&&ck(nam[x-dx[k]][y-dy[k]],nam[x-dx[i]][y-dy[i]])&&!dp[x][y][i])
dp[x][y][i]=,q.push(Tri(x,y,i));
}
}
bool cck(int x,int y){return dp[x][y][]||dp[x][y][]||dp[x][y][]||dp[x][y][]||(x==stx&&y==sty);}
int main()
{
// freopen("tt.in","r",stdin);
read(n),read(m),read(Q);
for(int i=;i<=n;i++)
{
scanf("%s",mp[i]+);
for(int j=;j<=m;j++)if(mp[i][j]!='#')
{
nam[i][j] = ++tot;
if(mp[i][j]=='A')rt=tot,rtx=i,rty=j;
if(mp[i][j]=='B')st=tot,stx=i,sty=j;
}
}
for(int i=;i<=n;i++)for(int j=;j<=m;j++)if(mp[i][j]!='#')
{
int u = nam[i][j];
for(int x,y,k=;k<;k++)
{
x = i+dx[k],y = j+dy[k];
if(!check(x,y)||mp[x][y]=='#')continue;
ae(u,nam[x][y]);
}
}
tarjan(rt,);
bfs();sol();
for(int x,y,i=;i<=Q;i++)
{
read(x),read(y);
puts(cck(x,y)?"YES":"NO");
}
return ;
}

bzoj5138 [Usaco2017 Dec]Push a Box的更多相关文章

  1. 【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)

    [BZOJ5138][Usaco2017 Dec]Push a Box(强连通分量) 题面 BZOJ 洛谷 题解 这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做. 首先看完题目,是 ...

  2. BZOJ5142: [Usaco2017 Dec]Haybale Feast(双指针&set)(可线段树优化)

    5142: [Usaco2017 Dec]Haybale Feast Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 182  Solved: 131[ ...

  3. luogu P4082 [USACO17DEC]Push a Box

    传送门 一个人推箱子,和之前的华容道中的棋子移动有异曲同工之妙,因为每次可以让人走到箱子的其他方向上,或者推一下箱子 所以状态可以设成\(f_{i,j,k}\),即箱子在\((i,j)\),人在\(k ...

  4. [Usaco2017 Dec] A Pie for a Pie

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=5140 [算法] 最短路 时间复杂度 : O(N^2) [代码] #include&l ...

  5. [USACO17DEC]Push a Box

    https://www.zybuluo.com/ysner/note/1293166 题面 戳我 解析 挺不错的一道图论码量题. 可以借此回顾一下\(noip2013\)华容道. 思路和华容道差不多. ...

  6. Luogu P4082 [USACO17DEC]Push a Box 点双连通分量/圆方树

    (貌似有圆方树的做法,我写的是点双) 显然这道题就是直接搜索.定义状态为f[i][j][0~4]表示箱子在(i,j),人在某个方向推.然后问题就是怎么转向.我们发现如果要转向,必须是人走过一条不包括( ...

  7. BZOJ5142: [Usaco2017 Dec]Haybale Feast 线段树或二分答案

    Description Farmer John is preparing a delicious meal for his cows! In his barn, he has NN haybales ...

  8. [BZOJ5139][Usaco2017 Dec]Greedy Gift Takers 权值线段树

    Description Farmer John's nemesis, Farmer Nhoj, has NN cows (1≤N≤10^5), conveniently numbered 1…N. T ...

  9. BZOJ5137[Usaco2017 Dec]Standing Out from the Herd

    看了半天题 不知道怎么用SAM维护 于是借(chao)鉴(xi)的一发神犇的 只要判断这个子串之前被标记的记号(也就是他属于第几个串)和这次转移到的是否相同 如果不同就说明该子串属于多个串 直接标记- ...

随机推荐

  1. [Xcode 实际操作]九、实用进阶-(2)遍历设备(输出系统)上的所有字体

    目录:[Swift]Xcode实际操作 在实际工作中,经常需要调整界面元素的字体种类. 本文将演示输出系统提供的所有字体,方便检索和使用. 在项目导航区,打开视图控制器的代码文件[ViewContro ...

  2. HTTP1.1规范下载由6个文档组成

  3. Markdown - 如何使用上标、下标

    解决方法 Markdown可以和HTML的语法兼容,可以通过HTML的上标和下标标签来实现效果: 标签 写法 效果 上标 2<sup>10</sup> 210 下标 H< ...

  4. HDU-1556:Color the ball(前缀和)

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  5. UVa12298(生成函数的简单应用+FFT)

    I have a set of super poker cards, consisting of an infinite number of cards. For each positive compo ...

  6. Technocup 2017 - Elimination Round 1 (Unofficially Open for Everyone, Rated for Div. 2) D

    The organizers of a programming contest have decided to present t-shirts to participants. There are ...

  7. CSS以及JS各种库的在线CDN引用地址

    JS类—— html5.js,让你的IE浏览器支持H5新特性:http://html5shiv.googlecode.com/svn/trunk/html5.js   (记得要注释判断哦) JQuer ...

  8. Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理

    http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...

  9. P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib

    题目描述 农民约翰的母牛总是产生最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们.农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组 ...

  10. 【C#】.net 导出Excel功能

    将DataSet对象导出成Excel文档 一.不带格式控制 void btnExport_Click(object sender, EventArgs e) { IList<string> ...