LG3684 [CERC2016]机棚障碍 Hangar Hurdles
题意
题目描述
你正在评估一些关于一个巨型飞机仓库的建设计划。飞机仓库的地面可以表示为n行n列的网格图,其中每个格子要么是空的,要么有障碍物。行从上到下依次被编号为1到n,列从左到右依次被编号为1到n。
存放飞机零件的大型集装箱能在飞机仓库的地面上自由移动是很重要的。我们可以将每个集装箱看作一个以某个格子为中心的边平行于坐标轴的正方形。对于一个奇数k,一个尺寸为k的集装箱是一个包含k行k列的正方形。一个集装箱的坐标为其中心格子的坐标。集装箱可以向上下左右移动,但不能碰到障碍物,且不能移出仓库的边界。
给定q对格子A_k和B_k,对于每对格子,请找到能从A_k移动到B_k的集装箱的最大尺寸,注意这个尺寸也要是一个奇数。
输入输出格式
输入格式:
第一行包含一个正整数n(2<=n<=1000),表示仓库的尺寸。
接下来n行,每行n个字符,描述整个仓库,其中“.”表示空格子,“#”表示障碍物。
接下来一行包含一个正整数q(1<=q<=300000),表示询问的个数。
接下来q行,每行4个正整数r_A,c_A,r_B,c_B(1<=r_A,c_A,r_B,c_B<=n),分别表示A和B的坐标。
输入数据保证A和B是不同的空格子。
输出格式:
输出q行,每行一个整数,对于每个询问输出最大尺寸,如果不存在解,那么输出0。
输入输出样例
分析
正解就是从每一个障碍出发做八连通bfs,得到每个位置能放多大尺寸的物件(这就是点权),然后从\((a,b)\)到\((c,d)\)的一条路上,经过的点权最小点的点权,就是走这条路径的答案。
所以把每个格子看做一个点,一个格子和其上下左右四个格子连边,边权为这两个格子中较小的点权。做出最大生成树后,查询路径上最小值即可。
然后做法就很多了,我用的是kruskal重构树。
这个算法还有个名字,叫做最小瓶颈生成树。
时间复杂度\(O(n^2 \log n+q \log n)\)
代码
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
co int N=1001,M=2e6+1;
int n,Q,SZ,m;
char mp[N][N];int QAQ[N][N],id[N][N],qx[M],qy[M];
int v[M],ls[M],rs[M],f[M],dep[M],fa[M][21];
struct edge{int x,y,z;}e[M*2];
co int mvx[8]={1,-1,0,0,1,-1,-1,1},mvy[8]={0,0,1,-1,1,-1,1,-1};
bool cmp(co edge&A,co edge&B) {return A.z>B.z;}
void bfs(){
int he=1,ta=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(mp[i][j]=='#') ++ta,qx[ta]=i,qy[ta]=j;
else id[i][j]=++SZ,f[SZ]=SZ;
for(int i=1;i<=n;++i) ++ta,qx[ta]=i,qy[ta]=0;
for(int i=1;i<=n;++i) ++ta,qx[ta]=i,qy[ta]=n+1;
for(int i=1;i<=n;++i) ++ta,qx[ta]=0,qy[ta]=i;
for(int i=1;i<=n;++i) ++ta,qx[ta]=n+1,qy[ta]=i;
while(he<=ta){
int x=qx[he],y=qy[he];++he;
for(int i=0;i<8;++i){
int tx=x+mvx[i],ty=y+mvy[i];
if(1<=tx&&tx<=n&&1<=ty&&ty<=n&&mp[tx][ty]!='#'&&!QAQ[tx][ty])
QAQ[tx][ty]=QAQ[x][y]+1,++ta,qx[ta]=tx,qy[ta]=ty;
}
}
}
int findf(int x) {return x==f[x]?x:f[x]=findf(f[x]);}
void kruscal(){
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(mp[i][j]=='#') continue;
if(i!=1&&mp[i-1][j]!='#')
e[++m]=(edge){id[i][j],id[i-1][j],std::min(QAQ[i][j],QAQ[i-1][j])-1};
if(j!=1&&mp[i][j-1]!='#')
e[++m]=(edge){id[i][j],id[i][j-1],std::min(QAQ[i][j],QAQ[i][j-1])-1};
}
std::sort(e+1,e+1+m,cmp);
for(int i=1;i<=m;++i){
int r1=findf(e[i].x),r2=findf(e[i].y);
if(r1!=r2){
++SZ,v[SZ]=e[i].z,ls[SZ]=r1,rs[SZ]=r2;
f[SZ]=f[r1]=f[r2]=SZ;
}
}
}
void dfs(int x){
for(int i=1;i<=20;++i) fa[x][i]=fa[fa[x][i-1]][i-1];
if(ls[x]) fa[ls[x]][0]=x,dep[ls[x]]=dep[x]+1,dfs(ls[x]);
if(rs[x]) fa[rs[x]][0]=x,dep[rs[x]]=dep[x]+1,dfs(rs[x]);
}
int lca(int x,int y){
if(dep[x]<dep[y]) std::swap(x,y);
for(int i=20;i>=0;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=20;i>=0;--i)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
read(n);
for(int i=1;i<=n;++i) scanf("%s",mp[i]+1);
bfs(),kruscal();
for(int i=1;i<=SZ;++i) if(findf(i)==i) dep[i]=1,dfs(i);
for(read(Q);Q--;){
int ax,ay,bx,by;
read(ax),read(ay),read(bx),read(by);
int k=lca(id[ax][ay],id[bx][by]);
if(!k) puts("0");
else printf("%d\n",2*v[k]+1);
}
return 0;
}
LG3684 [CERC2016]机棚障碍 Hangar Hurdles的更多相关文章
- [CERC2016]机棚障碍 Hangar Hurdles(kruskal重构树+树上倍增)
题面 \(solution:\) 某蒟蒻的心路历程: 这一题第一眼感觉很奇怪 带障碍物的图,最大的集装箱? 首先想到的就是限制我集装箱大小条件的是什么: 如果我要在某一个点上放一个集装箱且使它最大, ...
- 洛谷 P3684 机棚障碍Hangar Hurdles [CERC2016] 图论
正解: 解题报告: 传送门! 首先不难想到这题主要有两个问题需要解决,一个是预处理出各个点的箱子半径最大值,一个是求ans 然后分别港下QwQ 首先关于预处理要说下昂 预处理有三种方法,分别港下 第一 ...
- Solution -「CERC 2016」「洛谷 P3684」机棚障碍
\(\mathcal{Description}\) Link. 给一个 \(n\times n\) 的网格图,每个点是空格或障碍.\(q\) 次询问,每次给定两个坐标 \((r_1,c_1), ...
- BZOJ.4793.[CERC2016]Hangar Hurdles(Kruskal重构树 BFS)
题目链接 \(Description\) 有一个\(n\times n\)的正方形网格,上面有若干障碍点.\(q\)次询问,每次询问把一个正方形箱子从\((x1,y1)\)推到\((x2,y2)\) ...
- [CERC2016]Hangar Hurdles
你正在评估一些关于一个巨型飞机仓库的建设计划.飞机仓库的地面可以表示为n行n列的网格图,其中每个格子要么是空的,要么有障碍物.行从上到下依次被编号为1到n,列从左到右依次被编号为1到n.存放飞机零件的 ...
- 【BFS】【并查集】【Tarjan】【LCA】Gym - 101173H - Hangar Hurdles
给你一张地图,给你q次询问,每次问你从A点到B点,最大能移动多大的箱子. 把每个点所能容纳的最大箱子求出来(BFS,八连通,一开始将所有边界点和障碍点入队).然后从大到小排序.然后用并查集将相邻(四联 ...
- Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)
题目大意:给出一个n*n的矩阵,有一些点是障碍,给出Q组询问,每组询问求两点间能通过的最大正方形宽度. 首先需要求出以每个点(i,j)为中心的最大正方形宽度mxl[i][j],可以用二维前缀和+二分或 ...
- Excel随机生成数据2
200万耗时大约 10秒以内,输出结果到txt文件. Sub GetPassword() 'by kagawa Dim i&, j&, k&, l&, m&, ...
- 综述-如何克服HTML5的“性工能”障碍
http://ask.dcloud.net.cn/docs HTML5自出现以来,几经风雨,虽看似很有前途,但实际使用问题太多,DCloud为此踩了无数坑.但我们从未放弃,我们加入了W3C,发起了 H ...
随机推荐
- Spring源码的编译、下载和阅读
原文出处: 分享牛 想对spring框架进行深入的学习一下,看看源代码,提升和沉淀下自己,工欲善其事必先利其器,还是先搭建环境吧. 环境搭建 sping源码之前是svn管理,现在已经迁移到了githu ...
- [Java学习] 强调一下编程风格
讲完了Java的基础语法,大家就可以编写简单的程序代码了,这里有必要强调一下编程风格. 代码风格虽然不影响程序的运行,但对程序的可读性却非常重要.自己编写的程序要让别人看懂,首先在排版方面要非常注意. ...
- Android之RecyclerView实现时光轴
做项目的过程中有个需求需要时光轴,于是网上找了部分资料 ,写了个案例,现在分享给大家. 如图: activity_main.xml <?xml version="1.0" e ...
- 我理解的NODE
简介:NODE不是我们想象中的后台语言,它不是一门语言,它是一个和浏览器类似的工具或者平台,在NODE平台中,可以把我们写的JS代码解析出来,而且NODE和谷歌浏览器一样都是采用V8引擎渲染解析的. ...
- Travelling Salesman and Special Numbers CodeForces - 914C (数位dp)
大意: 对于一个数$x$, 每次操作可将$x$变为$x$二进制中1的个数 定义经过k次操作变为1的数为好数, 求$[1,n]$中有多少个好数 注意到n二进制位最大1000位, 经过一次操作后一定变为1 ...
- 『Scrapy』终端调用&选择器方法
Scrapy终端 示例,输入如下命令后shell会进入Python(或IPython)交互式界面: scrapy shell "http://www.itcast.cn/channel/te ...
- ccf窗口
#include<iostream> #include<cstring> #include<algorithm> #include<vector> us ...
- python中的注意事项
.python 中的 and 从左到右计算表达式,若所有值均为真,则返回最后一个值,若存在假,返回第一个假值: or 也是从左到有计算表达式,返回第一个为真的值: 其中数字 0 是假,其他都是真: 字 ...
- ASP.NET的内置对象 —— Response 对象
在 ASP.NET 中,页面实际上是一个输出 HTML 的可执行对象. 传统的 ASP 程序通常将 ASP 代码和 HTML 标签集成在一个文件中,或者将其分离于多个文 件. 当执行文件时,服务器回从 ...
- dup的使用
转自:http://www.cnblogs.com/GODYCA/archive/2013/01/05/2846197.html 下面是关于实现重定向的函数dup和dup2的解释: 系统调用dup和d ...