大概就是要每两个点 只能有一条路径,并且约束,最短的边用来砌墙,那么反之的意思就是最大的边用来穿过
故最大生成树
生成以后 再用lca计算树上两点间的距离
(当然防止生成树是一条链,可以用树的重心作为根) ,然后简单的统计下树上两点的距离就行了
#include <bits/stdc++.h> using namespace std; const int N = 510*510*2; 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-1)*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][20]; 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][0] = fa; for(int i=1; f[x][i-1]; i++) { f[x][i] = f[f[x][i-1]][i-1]; } for(int i=head[x]; i; i=nex[i]) { if(son[i] != fa) { dep[son[i]] = dep[x] + 1; 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=19;i>=0;i--) { if(dep[u] - (1<<i) >= dep[v]) u=f[u][i]; } for(int i=19;i>=0;i--) { if(f[u][i] != f[v][i]) u=f[u][i], v=f[v][i], ans+=(1<<(i+1)); } if(u!=v) ans+=2; printf("%d ",ans); } int main () { freopen("in.txt","r",stdin); scanf("%d %d", &n, &m); sum=n*m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int x,y; scanf("%*s %d %*s %d", &x, &y); if(i < n) E[++etot]=node(Id(i,j), Id(i+1,j), x); if(j < m) E[++etot]=node(Id(i,j), Id(i,j+1), y); } } sort(E+1,E+1+etot,[](node a,node b) { return a.val > b.val; }); for(int i=0;i<=sum;i++) fa[i] = i; for(int i=1; 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(1,0); 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 0; }