最小生成树+倍增
发现如果水壶是定值,那地图上肯定存在许多以建筑物为中心的联通块。并且随着水壶的增大,联通块大小也增大,有一些联通块会融合。
因此考虑把所有建筑物丢到队列搞BFS。如果两个联通块碰到了,就给这两个建筑物连上一条边。如果两个联通块代表的建筑之间已经存在一条路径可达,就不连。这样连出来是一棵树,而且也是最小生成树。
然而这样是错的,有一个反例,因为对于同一个距离,队列更新有先后顺序。先更新的点距离远,后更新的点可能先碰到先更新的点导致连边错误。然后我发现只要不管三七二十一,是边直接连就行了,然后再求最小生成树即可。边数至多 O(h∗w∗4) 。
下午给自己的电脑装了ubuntu,用起来有点卡。。。好气
#include<cstdio>
#include<algorithm>
#define H 2005
#define N 200005
#define B 25
using namespace std;
namespace runzhe2000
{
struct item{int x, y, belong, v;}que[H*H];
struct edge{int next, to, val;}e[N<<1];
struct pdge{int a, b, c;}pe[H*H];
bool operator < (pdge a, pdge b){return a.c < b.c;}
char s[H][H];
int h, w, p, q, head, tail, ecnt, pecnt, f[N], fa[N][B], fv[N][B], last[N], bel[H][H], val[H][H], dep[N];
int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0};
int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}
void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;}
void addedge2(int a, int b, int c){addedge(a,b,c); addedge(b,a,c);}
void addedge0(int a, int b, int c){pe[++pecnt] = (pdge){a,b,c};}
void dfs(int x)
{
dep[x] = dep[fa[x][0]] + 1;
for(int i = 1; i < B; i++) fa[x][i] = fa[fa[x][i-1]][i-1], fv[x][i] = max(fv[fa[x][i-1]][i-1], fv[x][i-1]);
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to;
if(y != fa[x][0])
{
fa[y][0] = x;
fv[y][0] = e[i].val;
dfs(y);
}
}
}
int ask_lca(int a, int b)
{
if(dep[a] < dep[b]) swap(a, b);
for(int d = dep[a] - dep[b], i = 0; i < B; i++)
if(d & (1<<i)) a = fa[a][i];
for(int i = B-1; ~i; i--)
if(fa[a][i] != fa[b][i])
a = fa[a][i], b = fa[b][i];
return a == b ? a : fa[a][0];
}
int ask_max(int b, int a)
{
int r = 0, d = dep[a] - dep[b];
for(int i = B-1; ~i; i--)
if(d & (1<<i)) r = max(r, fv[a][i]), a = fa[a][i];
return r;
}
void main()
{
scanf("%d%d%d%d",&h,&w,&p,&q);
for(int i = 1; i <= h; i++)
scanf("%s",s[i]+1);
for(int i = 1, x, y; i <= p; i++)
{
scanf("%d%d",&x,&y);
que[tail++] = (item){x, y, i, 0};
bel[x][y] = i;
}
for(; head < tail; head++)
{
int x = que[head].x, y = que[head].y;
for(int k = 0; k < 4; k++)
{
int nx = x + dx[k], ny = y + dy[k];
if(nx < 1 || ny < 1 || nx > h || ny > w || s[nx][ny] == '#') continue;
if(bel[nx][ny] && bel[nx][ny] != bel[x][y])
addedge0(que[head].belong, bel[nx][ny], val[nx][ny] + que[head].v);
else if(!bel[nx][ny])
{
bel[nx][ny] = que[head].belong;
val[nx][ny] = que[head].v + 1;
que[tail++] = (item){nx, ny, bel[nx][ny], val[nx][ny]};
}
}
}
sort(pe+1, pe+1+pecnt);
for(int i = 1; i <= p; i++) f[i] = i;
for(int i = 1; i <= pecnt; i++)
{
int f1 = find(pe[i].a), f2 = find(pe[i].b);
if(f1 == f2) continue;
f[f1] =f2;
addedge2(pe[i].a,pe[i].b,pe[i].c);
}
for(int i = 1; i <= p; i++)
if(!fa[i][0]) dfs(i);
for(int i = 1, a, b; i <= q; i++)
{
scanf("%d%d",&a,&b);
if(find(a) != find(b))
puts("-1");
else
{
int c = ask_lca(a, b), ans = 0;
ans = max(ans, ask_max(c, a));
ans = max(ans, ask_max(c, b));
printf("%d\n",ans);
}
}
}
}
int main()
{
runzhe2000::main();
}