【BZOJ4242】水壶(克鲁斯卡尔重构树,BFS)

题面

BZOJ然而是权限题。

Description

JOI君所居住的IOI市以一年四季都十分炎热著称。
IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有P个,编号为1...P。
JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。
JOI君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此IOI市的市民一般都携带水壶出行。大小为x的水壶最多可以装x单位的水,建筑物里有自来水可以将水壶装满。
由于携带大水壶是一件很困难的事情,因此JOI君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。
现在给出IOI市的地图和Q个询问,第i个询问(1<=i<=Q)为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。

Input

第一行四个空格分隔的整数H,W,P,Q,表示IOI市被分成了纵H*横W块区域,有P个建筑物,Q次询问。
接下来H行,第i行(1<=i<=H)有一个长度为W的字符串,每个字符都是’.’或’#’之一,’.’表示这个位置是建筑物或原野,’#’表示这个位置是墙壁。
接下来P行描述IOI市每个建筑物的位置,第i行(1<=i<=P)有两个空格分隔的整数Ai和Bi,表示第i个建筑物的位置在第Ai行第Bi列。保证这个位置在地图中是’.’
接下来Q行,第i行(1<=i<=Q)有两个空格分隔的整数Si和Ti,表示第i个询问为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”

Output

输出Q行,第i行(1<=i<=Q)一个整数,表示在建筑物Si和Ti之间移动最小需要多大的水壶。
如果无法到达,输出-1。此外,如果不需要经过原野就能到达,输出0。

Sample Input

5 5 4 4

.....

..##.

.#...

..#..

.....

1 1

4 2

3 3

2 5

1 2

2 4

1 3

3 4

Sample Output

3

4

4

2

HINT

1<=H<=2000

1<=W<=2000

2<=P<=2*10^5

1<=Q<=2*10^5

1<=Ai<=H(1<=i<=P)

1<=Bi<=W(1<=i<=P)

(Ai,Bi)≠(Aj,Bj)(1<=i<j<=P)

1<=Si<Ti<=P(1<=i<=Q)

题解

好神仙的一道题目啊。
很明显的一点,这道题目就是要在网格图上面计算一个最小生成树,然后就变成了货车运输一样的做法,可以倍增或者是克鲁斯卡尔重构树。
后面的部分就是原题,所以不再考虑,只考虑怎么样构造网格图最小生成树。
我们对于每一个可行的起点一起\(bfs\),对于每一个格子记录两个东西:一个记录距离当前位置最近的建筑的距离,以及是哪一个建筑。
当你\(bfs\)到某个格子的时候,发现这个格子已经被其他建筑给标记过了,那么就可以直接从距离当前这个格子最近的建筑连向距离拓展出来的格子最近的那个建筑。
然而这题卡常,边数有\(4*2000*2000\),所以开一个\(vector\)记录所有可能的距离,然后把所有的距离全部挂在上面跑。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define pi pair<int,int>
#define mp make_pair
#define fr first
#define sd second
#define MAX 2020
#define pb push_back
#define N 200200
inline int read()
{int x=0;bool t=false;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=true,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return t?-x:x;
}
int H,W,P,Q;
pi p[N];
vector<pi> E[MAX*MAX];
char g[MAX][MAX];
int dis[MAX][MAX],bel[MAX][MAX];
int d[4][2]={1,0,0,1,-1,0,0,-1};
struct Line{int v,next;}e[N<<2];
int h[N<<1],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
void bfs()
{queue<pi> Q;for(int i=1;i<=P;++i)Q.push(p[i]),bel[p[i].fr][p[i].sd]=i;while(!Q.empty()){pi u=Q.front();Q.pop();for(int i=0;i<4;++i){pi v=mp(u.fr+d[i][0],u.sd+d[i][1]);if(g[v.fr][v.sd]=='#'||v.fr<1||v.fr>H||v.sd<1||v.sd>W)continue;if(!bel[v.fr][v.sd]){Q.push(v);bel[v.fr][v.sd]=bel[u.fr][u.sd];dis[v.fr][v.sd]=dis[u.fr][u.sd]+1;}else E[dis[v.fr][v.sd]+dis[u.fr][u.sd]].pb(mp(bel[v.fr][v.sd],bel[u.fr][u.sd]));}}
}
int f[N<<1];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
int CNT,w[N<<1],dep[N<<1];
int fa[22][N<<1];
void dfs(int u)
{dep[u]=dep[fa[0][u]]+1;for(int i=h[u];i;i=e[i].next)dfs(e[i].v);
}
void Kruskal()
{for(int i=1;i<=P;++i)f[i]=i;CNT=P;for(int i=0;i<=H*W;++i)for(int j=0,l=E[i].size();j<l;++j){int u=getf(E[i][j].fr),v=getf(E[i][j].sd);if(u==v)continue;++CNT;f[CNT]=f[u]=f[v]=CNT;w[CNT]=i;Add(fa[0][u]=CNT,u);Add(fa[0][v]=CNT,v);}for(int i=1;i<=21;++i)for(int j=1;j<=CNT;++j)fa[i][j]=fa[i-1][fa[i-1][j]];
}
int LCA(int u,int v)
{if(dep[u]<dep[v])swap(u,v);for(int i=21;~i;--i)if(dep[fa[i][u]]>=dep[v])u=fa[i][u];if(u==v)return u;for(int i=21;~i;--i)if(fa[i][u]!=fa[i][v])u=fa[i][u],v=fa[i][v];return fa[0][u];
}
int main()
{H=read();W=read();P=read();Q=read();for(int i=1;i<=H;++i)scanf("%s",g[i]+1);for(int i=1;i<=P;++i)p[i].fr=read(),p[i].sd=read();bfs();Kruskal();for(int i=CNT;i;--i)if(!dep[i])dfs(i);int cnt=0;while(Q--){++cnt;int u=read(),v=read();if(getf(u)!=getf(v))puts("-1");else printf("%d\n",w[LCA(u,v)]);}return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/9569565.html

【BZOJ4242】水壶(克鲁斯卡尔重构树,BFS)相关推荐

  1. Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)

    题目链接:点击查看 题目大意:给出一个 n∗nn*nn∗n 的矩阵,有些位置存在障碍物,现在有 qqq 次询问,每次询问给出两个点 st=(x1,y1),ed=(x2,y2)st=(x1,y1),ed ...

  2. 2016-2017 Central Europe Regional Contest Hangar Hurdles 克鲁斯卡尔重构树 + 建图

    传送门 文章目录 题意: 思路: 题意: 有一个n∗nn*nn∗n的网格图,有若干位置有障碍,有qqq个询问,每次询问给出两个点坐标x1,y1,x2,y2x1,y1,x2,y2x1,y1,x2,y2, ...

  3. 克鲁斯卡尔重构树及简单应用

    克鲁斯卡尔重构树 概念 克鲁斯卡尔重构树,顾名思义,算是克鲁斯卡尔算法的衍生算法.下面给出如何构建克鲁斯卡尔重构树. 1.我们先将边排序,不同的排序规则会使最终的树有不同的性质. 2.排序后遍历每条边 ...

  4. 牛客 - 牛半仙的妹子图(并查集+bitset/克鲁斯卡尔重构树+主席树)

    题目链接:点击查看 题目大意:给出一个由 n 个点和 m 条边组成的连通图,每个点都有一种颜色,每条边都有一个权值,现在规定一个起点 st,再给出 q 次询问,每次询问给出区间 [ l , r ] , ...

  5. 牛客 - 红蓝图(克鲁斯卡尔重构树的dfs序上建主席树)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,每条边都有边权和颜色,颜色分为红色和蓝色,现在有 q 次相互独立的操作,每次操作会询问 ( x , t ) ,问删除掉所有权值 ...

  6. CodeForces - 1417F Graph and Queries(克鲁斯卡尔重构树的dfs序上建线段树)

    题目链接:点击查看 题目大意:给出一个 n 个点 m 条边组成的无向图,每个点初始时都有一个权值 val,满足: 每个点的 val[ i ] 各不相同 val[ i ] ∈ [ 1 , n ] 现在有 ...

  7. 克鲁斯卡尔重构树小结

    https://zybuluo.com/ysner/note/1239639 定义 克鲁斯卡尔重构树可以维护诸如"查询从某个点出发经过边权不超过\(w\)的边最远所能到达的节点"或 ...

  8. CF1408G:Clusterization Counting(区间dp、克鲁斯卡尔重构树)

    解析 很妙的一道题 看这两个南辕北辙的标签就知道这题不简单 看见dp思路还是得打开 一开始其实想到按边权排序了 但卡在了重构树上 遇到dp一定要敢想 勇于和图论等结合 考虑正解 按照边权升序排序 依次 ...

  9. P4197 【Peaks】克鲁斯卡尔重构树详解

    \(\texttt{Kruskal}\) 重构树 -- 需要一定基础的简单算法 题目大意: 给你一个无向图,可能有很多个连通块 给定一些询问 \(v,x,k\),代表在 \(v\{\}\) 这个连通块 ...

最新文章

  1. 【EXCEL】VLOOKUP函数反向应用
  2. Flask的Debug功能非常酷
  3. CSS实现div梯形分割
  4. PaperNotes(6)-GAN/DCGAN/WGAN/WGAN-GP/WGAN-SN-网络结构/实验效果
  5. JAVA入门级教学之(super关键字)
  6. 阿里云大数据MaxCompute计算资源分布以及LogView分析优化
  7. 你先说什么事,我再决定有没有空
  8. ureport2学习笔记
  9. wps如何对比两列数据找出不同
  10. mipi的dsi全称_MIPI-DSI/CSI协议介绍-转载
  11. 基于darknet的voc数据集训练和mAP测试
  12. Acwing算法—动态规划
  13. (宏) Word图片题注“图一-1”转化为“图1-1”
  14. html5中三角函数,三角函数和角公式
  15. 怎么在mysql查看运行日志_如何查看mysql运行、访问记录等日志
  16. 掌阅Android App插件补丁实践(ZeusPlugin)
  17. VS2022配置OpenCV 4.3.0报错解决办法
  18. SQL SERVER2008R2安装报错 安装程序集“Microsoft.VC80.ATL,version=“8.0.50727.1833“。。。
  19. 嵌入式开发设备的组成
  20. micropython 驱动_Micropython 飞控 驱动 3.MPU9250

热门文章

  1. 动态库在不同操作系统中的不同意义
  2. laravel 淘宝 NPM 镜像
  3. [转]Sql Server参数化查询之where in和like实现详解
  4. [转载]C# WinForm开发系列 - 文章索引
  5. 51Testing第五期电子杂志下载
  6. python 面试题(2)--- 字符串连接问题
  7. php软件开发--公众平台
  8. ansible最大并发_通过这7种方法来最大程度地提高Ansible技能
  9. 如何在Linux上运行Windows软件?
  10. 表面上承认错误_做一个可以承认错误的领导者