大概就是要每两个点 只能有一条路径,并且约束,最短的边用来砌墙,那么反之的意思就是最大的边用来穿过
故最大生成树
生成以后 再用lca计算树上两点间的距离
(当然防止生成树是一条链,可以用树的重心作为根) ,然后简单的统计下树上两点的距离就行了
#include <bits/stdc++.h>
using namespace std; const int N = **;
int n, m, sum, fa[N]; struct node {
int u,v,val;
node(){}
node(int uu,int vv,int va):u(uu),v(vv),val(va){}
}E[N]; int etot; int Id(int x,int y) {
return (x-)*m+y;
} int Find(int x) {
return fa[x] == x ? x : fa[x]=Find(fa[x]);
} bool join(int u,int v) {
int fu = Find(u);
int fv = Find(v);
if(fu!=fv) {
fa[fu] = fv;
return true;
}
return false;
} int tot, head[N], nex[N], son[N], dep[N], f[N][];
void add(int u,int v) {
nex[++tot] = head[u];
son[tot] = v;
head[u] = tot;
} void addEdge(int u,int v) {
add(u,v);
add(v,u);
} void dfs(int x,int fa) {
f[x][] = fa;
for(int i=; f[x][i-]; i++) {
f[x][i] = f[f[x][i-]][i-];
}
for(int i=head[x]; i; i=nex[i]) {
if(son[i] != fa) {
dep[son[i]] = dep[x] + ;
dfs(son[i],x);
}
}
}
void Lca(int u,int v) {
if(dep[u] < dep[v])
swap(u,v);
int ans = dep[u]-dep[v];
for(int i=;i>=;i--) {
if(dep[u] - (<<i) >= dep[v])
u=f[u][i];
}
for(int i=;i>=;i--) {
if(f[u][i] != f[v][i])
u=f[u][i], v=f[v][i], ans+=(<<(i+));
}
if(u!=v) ans+=;
printf("%d\n",ans);
} int main ()
{
freopen("in.txt","r",stdin);
scanf("%d %d", &n, &m);
sum=n*m;
for(int i=;i<=n;i++) {
for(int j=;j<=m;j++) {
int x,y; scanf("%*s %d %*s %d", &x, &y);
if(i < n)
E[++etot]=node(Id(i,j), Id(i+,j), x);
if(j < m)
E[++etot]=node(Id(i,j), Id(i,j+), y);
}
}
sort(E+,E++etot,[](node a,node b) {
return a.val > b.val;
});
for(int i=;i<=sum;i++)
fa[i] = i;
for(int i=; i<=etot; i++) {
int u = E[i].u;
int v = E[i].v;
//if(join(u,v))
//addEdge(u,v);
int fu = Find(u), fv = Find(v);
if(fu == fv) continue;
fa[fu] = fa[fv];
addEdge(u,v);
}
dfs(,);
int Q; scanf("%d",&Q);
while (Q--) {
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
Lca(Id(x1,y1),Id(x2,y2));
}
return ;
}