Solution water bottle
Topic effect: a \ (n \ times m \) matrix has some walls can not go, there are some buildings, there are some places wilderness. Each walked a grid need to consume a wilderness water, buildings can fill up the kettle. He asked many times from one building to another building capacity of at least the number of kettle.
Kruskal tree reconstruction
analysis:
First difficult to think of violence, we can all reach each other even building twenty-two side, if we want to make the biggest edge weights as small as possible so we require a minimum spanning tree. Consider prove greedy: continue to increase until the two sides of connectivity, this is the Kruskal process.
Seeking the right side of the tree between two points is the maximum value of the reconstructed tree board Kruskal title
But if we can not afford to violence enumerate all the buildings, but we found some edges is of no use, we can shrink a method similar to the point of consideration. We give each building a color, then the same color dot the nearest gas station are the same
We just need to enumerate each point and its neighboring points and, even if a different side to the color, this can be calculated in the way bfs when found to have been dyed dyed different colors and even the edge points
#include <cstdio>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;
const int maxn = 2e3 + 100,maxp = 4e5 + 100,maxdep = 25;
int n,m,p,q,vis[maxn][maxn],dis[maxn][maxn],deltax[] = {-1,0,1,0},deltay[] = {0,-1,0,1};
namespace Graph{
struct Edge{int from,to,dist;};
vector<Edge> G[maxp];
inline void addedge(int from,int to,int dist){G[from].push_back(Edge{from,to,dist});}
int faz[maxp][maxdep + 1],dep[maxp],vis[maxp],col[maxp],val[maxp],col_tot;
inline void init(int u){
vis[u] = 1;col[u] = col_tot;
for(int i = 1;i <= maxdep;i++)
faz[u][i] = faz[faz[u][i - 1]][i - 1];
for(auto e : G[u]){
if(e.to == faz[u][0])continue;
faz[e.to][0] = u;
dep[e.to] = dep[u] + 1;
init(e.to);
}
}
inline void init(){
for(int i = (p << 1) - 1;i >= 1;i--)
if(!vis[i])dep[i] = 1,col_tot++,init(i);
}
inline int lca(int x,int y){
if(dep[x] < dep[y])swap(x,y);
for(int i = maxdep;i >= 0;i--)
if(dep[faz[x][i]] >= dep[y])
x = faz[x][i];
if(x == y)return x;
for(int i = maxdep;i >= 0;i--)
if(faz[x][i] != faz[y][i])
x = faz[x][i],y = faz[y][i];
return faz[x][0];
}
inline int query(int x,int y){return col[x] != col[y] ? -1 : val[lca(x,y)];}
}
namespace Kruskal{
using Graph::Edge;
vector<Edge> Edges;
inline void addedge(int from,int to,int dist){Edges.push_back(Edge{from,to,dist});}
int f[maxp],sz;
inline void init(){for(int i = 1;i <= p;i++)f[i] = i;sz = p;}
inline int find(int x){return x == f[x] ? x : f[x] = find(f[x]);}
inline void kruskal(){
sort(Edges.begin(),Edges.end(),[](const Edge &a,const Edge &b){return a.dist < b.dist;});
init();
int tot = p,lim = (p << 1) - 1;
for(int i = 1;i <= lim;i++)f[i] = i;
for(auto e : Edges){
int fx = find(e.from),fy = find(e.to);
if(fx != fy){
f[fx] = f[fy] = ++tot;
Graph::val[tot] = e.dist;
Graph::addedge(tot,fx,0),Graph::addedge(tot,fy,0);
if(tot == lim)break;
}
}
}
}
inline bool check(int x,int y){return x >= 1 && x <= n && y >= 1 && y <= m;}
char mp[maxn][maxn];
struct Pos{int x,y;}building[maxp];
inline void bfs(){
queue<Pos> Q;
for(int i = 1;i <= p;i++)
Q.push(building[i]),vis[building[i].x][building[i].y] = i;
while(!Q.empty()){
Pos now = Q.front();Q.pop();
int x = now.x,y = now.y;
for(int i = 0;i < 4;i++){
int nx = x + deltax[i],ny = y + deltay[i];
if(!check(nx,ny) || mp[nx][ny] == '#' || vis[nx][ny] == vis[x][y])continue;
if(vis[nx][ny] && vis[x][y] != vis[nx][ny]){Kruskal::addedge(vis[x][y],vis[nx][ny],dis[x][y] + dis[nx][ny]);continue;}
vis[nx][ny] = vis[x][y];
dis[nx][ny] = dis[x][y] + 1;
Q.push(Pos{nx,ny});
}
}
}
int main(){
scanf("%d %d %d %d",&n,&m,&p,&q);
for(int i = 1;i <= n;i++)scanf("%s",mp[i] + 1);
for(int i = 1;i <= p;i++)scanf("%d %d",&building[i].x,&building[i].y);
bfs();
Kruskal::kruskal();
Graph::init();
for(int u,v,i = 1;i <= q;i++)
scanf("%d %d",&u,&v),printf("%d\n",Graph::query(u,v));
return 0;
}