题目大意
某市是一个被分成 H × W H\times W H×W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有 P P P个,编号为 1 … P 1\dots P 1…P。只有建筑物和原野能够进入,而且每次只能走到相邻的区域中,且不能移动到市外。现在需要在各个建筑物之间往返。在原野上每走过一个区域都需要 1 1 1单位的水。原野上不能提供水,但建筑物里有自来水可以将随身携带的水壶装满。
给出该市的地图和 Q Q Q个询问,对于第 i i i个询问,输出在建筑物 S i S_i Si和 T i T_i Ti之间移动需要水壶的最小容积。
H , W ⩽ 2000 H,W\leqslant 2000 H,W⩽2000, P , Q ⩽ 2 × 1 0 5 P,Q\leqslant 2\times 10^5 P,Q⩽2×105。
思路
由于可以在建筑物中补充水,从 S i S_i Si走到 T i T_i Ti可能会经过多个建筑物,则需要水壶的最小容积为连续经过的两个建筑物之间的距离的最大值。要使路径上的最大距离最小,可以想到最小生成树。
如果以每个建筑物为起点进行BFS,边的数量就达到 O ( P 2 ) O(P^2) O(P2),不可取。可以先把 P P P个建筑物全部放入队列中,同时向外扩展,用 i d [ i ] id[i] id[i]记下网格中区域 i i i最先被哪个建筑物扩展到, d i s t [ i ] dist[i] dist[i]记录扩展的距离。然后讨论相邻的两个区域 i , j i,j i,j,将最先扩展到这两个区域的建筑物 i d [ i ] , i d [ j ] id[i],id[j] id[i],id[j]之间连边,边长为 d i s t [ i ] + d i s t [ j ] dist[i]+dist[j] dist[i]+dist[j],这样边的数量就减少到了 O ( H W ) O(HW) O(HW)。
以下内容可能引起不适
少了这么多边,真的不会漏掉最小生成树上的边吗?
假设最小生成树上有一条边连接建筑物
A
,
B
A,B
A,B:
-
如果图中有这条边,那么其长度一定是建筑物 A , B A,B A,B间的最短距离。这个比较显然。
-
如果图中没有这条边,先假设图中只有 A , B A,B A,B两个建筑物,那么 A , B A,B A,B路径上的区域一定可以从中间划分为两部分,一部分的 i d id id值为 A A A,另一部分为 B B B。那么讨论到路径的正中间的两个相邻区域 x 1 , x 2 x_1,x_2 x1,x2时, A , B A,B A,B之间就会连边。
现在图中没有 A , B A,B A,B这条边,说明 x 1 , x 2 x_1,x_2 x1,x2中至少有一个区域的 i d id id值发生了变化,原因是其它的建筑物先扩展到该区域。则 A , B A,B A,B的路径上一定会有一段连续的被其它建筑物扩展到的区域 [ y 1 , y 2 ] [y_1,y_2] [y1,y2],且两侧仍然会各有一个区域 x 1 , x 2 x_1,x_2 x1,x2被 A A A或 B B B扩展到。
根据 i d id id数组的定义,有d i s t ( y 1 , i d [ y 1 ] ) < d i s t ( B , y 1 ) d i s t ( y 2 , i d [ y 2 ] ) < d i s t ( A , y 2 ) \begin{aligned} dist(y_1,id[y_1])&<dist(B,y_1)\\ dist(y_2,id[y_2])&<dist(A,y_2) \end{aligned} dist(y1,id[y1])dist(y2,id[y2])<dist(B,y1)<dist(A,y2)
即
d i s t ( A , x 1 ) + d i s t ( y 1 , i d [ y 1 ] ) < d i s t ( A , x 1 ) + d i s t ( B , y 1 ) d i s t ( B , x 2 ) + d i s t ( y 2 , i d [ y 2 ] ) < d i s t ( A , y 2 ) + d i s t ( B , x 2 ) \begin{aligned} dist(A,x_1)+dist(y_1,id[y_1])&<dist(A,x_1)+dist(B,y_1)\\ dist(B,x_2)+dist(y_2,id[y_2])&<dist(A,y_2)+dist(B,x_2) \end{aligned} dist(A,x1)+dist(y1,id[y1])dist(B,x2)+dist(y2,id[y2])<dist(A,x1)+dist(B,y1)<dist(A,y2)+dist(B,x2)
即
d i s t ( A , i d [ y 1 ] ) < d i s t ( A , B ) d i s t ( B , i d [ y 2 ] ) < d i s t ( A , B ) \begin{aligned} dist(A,id[y_1])&<dist(A,B)\\ dist(B,id[y_2])&<dist(A,B) \end{aligned} dist(A,id[y1])dist(B,id[y2])<dist(A,B)<dist(A,B)
同时有
d i s t ( y 1 , i d [ y 1 ] ) < d i s t ( A , y 1 ) d i s t ( y 2 , i d [ y 2 ] ) < d i s t ( B , y 2 ) \begin{aligned} dist(y_1,id[y_1])&<dist(A,y_1)\\ dist(y_2,id[y_2])&<dist(B,y_2) \end{aligned} dist(y1,id[y1])dist(y2,id[y2])<dist(A,y1)<dist(B,y2)即
d i s t ( y 1 , i d [ y 1 ] ) + d i s t ( y 2 , i d [ y 2 ] ) < d i s t ( A , y 1 ) + d i s t ( B , y 2 ) dist(y_1,id[y_1])+dist(y_2,id[y_2])<dist(A,y_1)+dist(B,y_2) dist(y1,id[y1])+dist(y2,id[y2])<dist(A,y1)+dist(B,y2)
即
d i s t ( i d [ y 1 ] , i d [ y 2 ] ) < d i s t ( A , B ) dist(id[y_1],id[y_2])<dist(A,B) dist(id[y1],id[y2])<dist(A,B)
然后就发生了神奇的一幕: A , B , i d [ y 2 ] , i d [ y 1 ] A,B,id[y_2],id[y_1] A,B,id[y2],id[y1]四个建筑物顺次构成了一个环,而这个环中连接 A , B A,B A,B的边长度最长,所以这条边肯定不在最小生成树中。
回到正题
然后用Kruskal求出生成树,问题就变成了求树上两点间路径上的最大边权。预处理倍增数组 f [ u ] [ i ] f[u][i] f[u][i],表示 u u u号点到 f a [ u ] [ i ] fa[u][i] fa[u][i]的路径上的最大边权,在求LCA的时候顺便统计答案。
另外本题求出的生成树可能是森林,所以每棵树都要DFS一遍求倍增数组,还要判断无解的情况。