​https://nanti.jisuanke.com/t/31462​

题目说两点之间路径唯一 那就是一棵树 又因为树的补图权值之和要最小 那其实就是求一个最大生成树

然后每次查询求个lca即可

#include <bits/stdc++.h>
using namespace std;
#define ll long long

struct node1
{
int u;
int v;
ll w;
};

struct node2
{
int v;
int next;
};

node1 pre[500010];
node2 edge[500010];
int dp[250010][20];
int first[250010],f[250010],deep[250010];
int n,m,q,tot,num;

bool cmp(node1 n1,node1 n2)
{
return n1.w>n2.w;
}

void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}

int getf(int p)
{
if(f[p]==p) return p;
else
{
f[p]=getf(f[p]);
return f[p];
}
}

bool unite(int u,int v)
{
int fu,fv;
fu=getf(u);
fv=getf(v);
if(fu!=fv)
{
f[fv]=fu;
return true;
}
else return false;
}

void dfs(int cur,int fa)
{
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa)
{
dp[v][0]=cur;
deep[v]=deep[cur]+1;
dfs(v,cur);
}
}
return;
}

void solve()
{
int i,j;
dp[1][0]=0;
deep[1]=1;
dfs(1,0);
for(j=1;(1<<j)<=n*m;j++)
{
for(i=1;i<=n*m;i++)
{
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
return;
}

int getlca(int u,int v)
{
int i;
if(deep[u]<deep[v]) swap(u,v);
for(i=log2(n*m);i>=0;i--)
{
if(deep[dp[u][i]]>=deep[v])
{
u=dp[u][i];
}
}
if(u==v) return u;
for(i=log2(n*m);i>=0;i--)
{
if(dp[u][i]!=dp[v][i])
{
u=dp[u][i];
v=dp[v][i];
}
}
return dp[u][0];
}

int main()
{
ll w1,w2;
int i,j,cnt,u,v,lca;
char ch1[10],ch2[10];
scanf("%d%d",&n,&m);
tot=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%s%lld%s%lld",ch1,&w1,ch2,&w2);
if(ch1[0]=='D')
{
tot++;
pre[tot].u=(i-1)*m+j,pre[tot].v=i*m+j,pre[tot].w=w1;
}
if(ch2[0]=='R')
{
tot++;
pre[tot].u=(i-1)*m+j,pre[tot].v=(i-1)*m+j+1,pre[tot].w=w2;
}
}
}
sort(pre+1,pre+tot+1,cmp);
memset(first,-1,sizeof(first));
for(i=1;i<=n*m;i++) f[i]=i;
num=0,cnt=0;
for(i=1;i<=tot;i++)
{
if(unite(pre[i].u,pre[i].v))
{
addedge(pre[i].u,pre[i].v);
addedge(pre[i].v,pre[i].u);
cnt++;
if(cnt==n*m-1) break;
}
}
solve();
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&i,&j);
u=(i-1)*m+j;
scanf("%d%d",&i,&j);
v=(i-1)*m+j;
lca=getlca(u,v);
printf("%d\n",deep[u]+deep[v]-2*deep[lca]);
}

return 0;
}