题目描述:

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. 即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

    本文引用了“蔷薇Nina”的“Nginx 相关介绍(Nginx是什么?能干嘛?)”一文部分内容,感谢作者的无私分享. 1.引言   Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡 ...

  2. 第一篇 HTML5打包APP之VMware15安装MAC(MAC OS 10.13)(OS X 10.14)原版可升级最新可解锁macOS Unlocker3.0(OS X 10.13)

    1.1.2安装环境: 1.1.3所需资源: 1.1.4 Unlocker 3.0解锁 1.1.5 配置环境 1.1.6开始安装 1.1.7开启虚拟机进入MAC安装界面 1.1.8 macOS 10.1 ...

  3. C笔记列表

    笔记列表 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址.就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明. 要理解指针就要先理解计算机的内存.计算机内存会被 ...

  4. PAT甲级——1134 Vertex Cover (25 分)

    1134 Vertex Cover (考察散列查找,比较水~) 我先在CSDN上发布的该文章,排版稍好https://blog.csdn.net/weixin_44385565/article/det ...

  5. [題解] luogu p1220 關路燈

    區間dp 题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. ...

  6. Python 杂集

    Python字符串方法 Python递归和迭代 Python判断字符串编码以及编码的转换 exec 和 eval

  7. [软件工程基础]2017.10.30 第三次 Scrum 会议

    决议 游心与李煦通沟通生成报告脚本问题,并调试相应代码 李煦通部署服务器,并做一定安全检查 石奇川设计实验流程和题库前端页面 王嘉睿爵测试网站基本流程,提出关于用户体验方面的建议 刘子渊阅读代码,为机 ...

  8. jQuery scrollLeft()与scrollTop() 源码解读

    这里的实现也很容易懂,通过jQuery的静态方法each给jQuery的原型添加scrollLeft和scrollTop方法. 这里在取值时它把window和普通的element做了区分 如果是win ...

  9. 《javascript设计模式》笔记之第四章:继承

    一:首先,一个简单的继承实例: 首先是创建一个父类Person: function Person(name) { this.name = name; } Person.prototype.getNam ...

  10. Java面试:投行的15个多线程和并发面试题(转)

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...