【bzoj4242】水壶 BFS+最小生成树+倍增LCA
题目描述
输入
输出
样例输入
5 5 4 4
.....
..##.
.#...
..#..
.....
1 1
4 2
3 3
2 5
1 2
2 4
1 3
3 4
样例输出
3
4
4
2
题解
BFS+最小生成树+倍增LCA
一眼货车运输的既视感,然而需要先知道两个点之间的距离。
好在这种网格图是可以BFS的,所以把每个建筑物压到队列中,跑BFS,记录每个点被哪个点所搜到,以及与搜到点的距离是多少。
当搜到另一个被其它点搜到过的点时,将它们被搜到的建筑物之间连边,这样边集只有$O(4wh)$。然后跑Kruskal。
(这里需要注意的是直接将这两个点在并查集中合并是不行的,因为搜到的不一定是最短距离;而按照距离排序搜索也是不对的。必须把所有可能的边连上跑最小生成树才可行。)
这个过程中可以按照距离将所有的边放到类似于桶的东西中,形成若干个链表(或者使用vector),这样能够省去排序的过程。
然后get到最小生成树之后跑倍增LCA即可。注意跑LCA时求的答案是路径最大值,不是最小值。
另外,本题不仅仅是一棵树,可能是森林,所以需要把每棵树都遍历一遍。别忘判断-1的情况。
时间复杂度$O(wh+m\log n)$
#include <cstdio>
#include <algorithm>
#define K 2010
#define N 200010
using namespace std;
int first[K * K] , px[K * K * 2] , py[K * K * 2] , last[K * K * 2] , tot;
int map[K][K] , vis[K][K] , dis[K][K] , f[N] , qx[K * K] , qy[K * K] , l = 1 , r , head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , fa[19][N] , val[19][N] , deep[N] , log[N];
char str[K];
struct data
{
int x , y;
data() {}
data(int x0 , int y0) {x = x0 , y = y0;}
}tmp[5];
bool cmp(data a , data b)
{
return map[a.x][a.y] && map[b.x][b.y] ? vis[a.x][a.y] && vis[b.x][b.y] ? dis[a.x][a.y] < dis[b.x][b.y] : vis[a.x][a.y] : map[a.x][a.y];
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , len[cnt] = z , next[cnt] = head[y] , head[y] = cnt;
}
void ins(int t , int x , int y)
{
px[++tot] = x , py[tot] = y , last[tot] = first[t] , first[t] = tot;
}
void drive(int x1 , int y1 , int x2 , int y2)
{
if(!map[x2][y2]) return;
if(!vis[x2][y2]) vis[x2][y2] = vis[x1][y1] , dis[x2][y2] = dis[x1][y1] + 1 , qx[++r] = x2 , qy[r] = y2;
else if(vis[x1][y1] != vis[x2][y2]) ins(dis[x1][y1] + dis[x2][y2] , vis[x1][y1] , vis[x2][y2]);
}
void dfs(int x)
{
int i;
for(i = 1 ; i <= log[deep[x]] ; i ++ )
fa[i][x] = fa[i - 1][fa[i - 1][x]] , val[i][x] = max(val[i - 1][x] , val[i - 1][fa[i - 1][x]]);
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[0][x])
fa[0][to[i]] = x , val[0][to[i]] = len[i] , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
}
int query(int x , int y)
{
if(find(x) != find(y)) return -1;
int i , ans = 0;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if(deep[x] - deep[y] >= (1 << i))
ans = max(ans , val[i][x]) , x = fa[i][x];
for(i = log[deep[x]] ; ~i ; i -- )
if(deep[x] >= (1 << i) && fa[i][x] != fa[i][y])
ans = max(ans , max(val[i][x] , val[i][y])) , x = fa[i][x] , y = fa[i][y];
if(x != y) ans = max(ans , max(val[0][x] , val[0][y]));
return ans;
}
int main()
{
int h , w , n , m , i , j , x , y;
scanf("%d%d%d%d" , &h , &w , &n , &m);
for(i = 1 ; i <= h ; i ++ )
{
scanf("%s" , str + 1);
for(j = 1 ; j <= w ; j ++ ) map[i][j] = (str[j] == '.');
}
for(i = 1 ; i <= n ; i ++ )
scanf("%d%d" , &qx[i] , &qy[i]) , vis[qx[i]][qy[i]] = f[i] = i , dis[qx[i]][qy[i]] = 0;
for(r = n ; l <= r ; l ++ )
x = qx[l] , y = qy[l] , drive(x , y , x + 1 , y) , drive(x , y , x - 1 , y) , drive(x , y , x , y + 1) , drive(x , y , x , y - 1);
for(i = 0 ; i <= h * w ; i ++ )
{
for(j = first[i] ; j ; j = last[j])
{
x = px[j] , y = py[j];
if(find(x) != find(y)) f[f[x]] = f[y] , add(x , y , i);
}
}
for(i = 2 ; i <= n ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = 1 ; i <= n ; i ++ ) if(!fa[0][i]) dfs(i);
while(m -- ) scanf("%d%d" , &x , &y) , printf("%d\n" , query(x , y));
return 0;
}
【bzoj4242】水壶 BFS+最小生成树+倍增LCA的更多相关文章
- LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA
非常好的一道图论问题. 显然,我们要求城市间的最小生成树,然后查询路径最大值. 然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围. 显然,如果两个城市的管辖范围没有交集的话 ...
- BFS+最小生成树+倍增+LCA【bzoj】4242 水壶
[bzoj4242 水壶] Description JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有 ...
- 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集
[题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...
- 【bzoj3732】Network 最小生成树+倍增LCA
题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...
- 训练指南 UVA - 11354(最小生成树 + 倍增LCA)
layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true ma ...
- BZOJ 3732 Network —— 最小生成树 + 倍增LCA
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3732 Description 给你N个点的无向图 (1 <= N <= 15, ...
- gym 101081 gym F. Auction of Services 最小生成树+倍增LCA
F. Auction of Services time limit per test 2.0 s memory limit per test 256 MB input standard input o ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增
题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...
随机推荐
- 初学者应该怎么学习前端?web前端的发展路线大剖析!
写在最前: 优秀的Web前端开发工程师要在知识体系上既要有广度和深度!应该具备快速学习能力. 前端开发工程师不仅要掌握基本的Web前端开发技术,网站性能优化.SEO和服务器端的基础知识,而且要学会运用 ...
- Verilog 参数化设计
为了提高模块的重复利用,关键就在于避免硬编码(hard literal),使模块参数化.参数化建模的好处是可以使代码清晰,便于后续维护和修改.只需要修改参数,不用修改其他代码就可以适用于不同的环境中. ...
- 关于HTML5中Video标签无法播放mp4的解决办法
1.首先先排除掉代码问题.路径问题.浏览器不支持问题等常规问题,这些问题另行百度. <video width="500px" height="300px" ...
- Gym 100342F Move to Front (树状数组动态维护和查询)
用树状数组动态和查询修改排名. 树状数组可以很方便地查询前缀和,那么可以利用这一特点,记录一个点在树状数组里最后一次出现的位置, 查询出这个位置,就可以知道这个点的排名了.更改这个点的排名的时候只要把 ...
- Objective-C中的命名前缀说明
http://www.cnblogs.com/dhui69/p/6410134.html __kindof __kindof 这修饰符还是很实用的,解决了一个长期以来的小痛点,拿原来的 UITable ...
- pc端引入微信公众号文章
最近做了一个小需求,结果坑特别多..... 需求是这样的,要给公司内部做一个微信公众号广告投票系统,整个项目就不多赘述了,有个小功能,要求是这样的: 点击某条记录后的“投票”按钮,在当前页面弹出弹窗显 ...
- URL URI URN的区别
下面这张图可以完美的解释他们三者之间的关系 URI包含URL和URN Uniform Resource Identifier :统一资源标志符,用于标识某一互联网资源 Uniform Resoutce ...
- druid 配置WebStatFilter 网络统计以及监控
WebStatFilter用于采集web-jdbc关联监控的数据. web.xml配置 <filter> <filter-name>DruidWebStatFilter< ...
- C语言中函数参数传递
C语言中函数参数传递的三种方式 (1)值传递,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对形参的改变不会影响到函数外的变量的值.(2)地址传递,就是把 ...
- 第2节 azkaban调度:1、azkaban的调度任务使用
2.4 Azkaban实战 Azkaba内置的任务类型支持command.java Command类型单一job示例 创建job描述文件 创建文本文件,更改名称为mycommand.job 注意后缀. ...