离线求出任意点对u−v的最近公共祖先
不妨令v的深度优先搜索序小于u
深搜到u时,v已经被扫过,答案为v到root路径上没有处理完的第一个灰色点
可用并查集优化,若一个点全部扫完则加入集合中,代表元素为集合最先被搜到的点
也就是答案
交通运输线
#include<iostream>
#include<cstdio>
using namespace std;
int hed[10005],vet[20005],val[20005],Next[20005];
int dis[10005];
int ull[1000005],vll[1000005];
int hedq[10005],vetq[2000005],valq[2000005],Nextq[2000005];
int fa[10005],ans[1000005];
int tree[10005];
int num;
int numq;
void add(int u,int v,int z){
++num;
vet[num]=v;
val[num]=z;
Next[num]=hed[u];
hed[u]=num;
}
void addq(int u,int v,int z){
++numq;
vetq[numq]=v;
valq[numq]=z;
Nextq[numq]=hedq[u];
hedq[u]=numq;
}
int find(int x){
if (fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
void Union(int u,int v){
int rootu=find(u);
int rootv=find(v);
fa[rootv]=rootu;
}
void lca(int u,int fath,int hao){
fa[u]=u;
for (int i=hed[u];i!=-1;i=Next[i]){
int v=vet[i];
if (v==fath) continue;
dis[v]=dis[u]+val[i];
lca(v,u,hao);
Union(u,v);
}
tree[u]=hao;
for (int i=hedq[u];i!=-1;i=Nextq[i])
if (ans[valq[i]]==-1)
if (tree[vetq[i]]==hao)
ans[valq[i]]=find(vetq[i]);
}
int main(){
int t;
scanf("%d",&t);
while (t--){
num=0;
numq=0;
int n,m,c;
scanf("%d%d%d",&n,&m,&c);
for (int i=1;i<=n;++i){
hed[i]=-1;
hedq[i]=-1;
tree[i]=0;
fa[i]=i;
dis[i]=0;
}
for (int i=1;i<=c;++i) ans[i]=-1;
for (int i=1;i<=m;++i){
int u,v,z;
scanf("%d%d%d",&u,&v,&z);
add(u,v,z);
add(v,u,z);
}
for (int i=1;i<=c;++i){
int u,v;
scanf("%d%d",&u,&v);
ull[i]=u;
vll[i]=v;
addq(u,v,i);
addq(v,u,i);
}
for (int i=1;i<=n;++i)
if (tree[i]==0){
dis[i]=0;
lca(i,0,i);
}
for (int i=1;i<=c;++i)
if (ans[i]==-1) printf("Not connected\n");
else printf("%d\n",dis[ull[i]]+dis[vll[i]]-dis[ans[i]]-dis[ans[i]]);
}
return 0;
}