•题意
在一个包含 n 个节点 m 条边的森林中;
有 q 次询问,每次询问求解两点间的最短距离;
如果这两点不联通,输出 "Not connected";
•题解1
树上任意两点间的最短距离就是最近公共祖先分别到这两点的距离和;
那么这个问题就被转化成了LCA问题。
因为有多棵树,所以,对于每棵树,都提前预处理出 $dis,dep$;
并通过并查集判断询问的两点是否联通;
•Code
基于二分的LCA1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 const int maxn=1e4+50; 6 7 int n,m,q; 8 int num; 9 int head[maxn]; 10 struct Edge 11 { 12 int to; 13 ll w; 14 int next; 15 }G[maxn<<1]; 16 void addEdge(int u,int v,ll w) 17 { 18 G[num]={v,w,head[u]}; 19 head[u]=num++; 20 } 21 vector<int >V[maxn]; 22 /** 23 fa[i][j]:节点j沿着其父结点向上走2^i步所到的节点(超过根节点时记为-1) 24 ///dis[i]:节点i的与根节点的距离 25 ///dep[i]:节点i的深度,根节点深度为0 26 */ 27 struct LCA 28 { 29 int fa[30][maxn]; 30 ll dis[maxn]; 31 ll dep[maxn]; 32 void DFS(int u,int f,ll Dis,ll Dep) 33 { 34 fa[0][u]=f;///节点u向上走2^0步来到的节点便是其父节点 35 dis[u]=Dis; 36 dep[u]=Dep; 37 for(int i=head[u];~i;i=G[i].next) 38 { 39 int v=G[i].to; 40 ll w=G[i].w; 41 if(v != f) 42 DFS(v,u,Dis+w,Dep+1); 43 } 44 } 45 void Init() 46 { 47 for(int i=1;i <= n;++i) 48 { 49 if(V[i].empty()) 50 continue; 51 ///预处理出每棵树的dis,dep,fa 52 DFS(V[i][0],-1,0,0); 53 for(int k=1;k <= 20;++k) 54 for(int j=0;j < V[i].size();++j) 55 { 56 int u=V[i][j]; 57 if(fa[k-1][u] == -1) 58 fa[k][u]=-1; 59 else 60 fa[k][u]=fa[k-1][fa[k-1][u]]; 61 } 62 } 63 } 64 int lca(int u,int v)///返回u,v的最近公共祖先 65 { 66 if(dep[u] > dep[v]) 67 swap(u,v); 68 69 for(int i=0;i <= 20;++i) 70 if((dep[v]-dep[u])>>i&1) 71 v=fa[i][v]; 72 if(u == v) 73 return u; 74 75 for(int i=20;i >= 0;--i) 76 if(fa[i][u] != fa[i][v]) 77 { 78 u=fa[i][u]; 79 v=fa[i][v]; 80 } 81 return fa[0][u]; 82 } 83 }_lca; 84 struct Set 85 { 86 int fa[maxn]; 87 void Init() 88 { 89 for(int i=0;i <= n;++i) 90 fa[i]=i; 91 } 92 int Find(int x) 93 { 94 return x == fa[x] ? x:fa[x]=Find(fa[x]); 95 } 96 void Union(int x,int y) 97 { 98 x=Find(x); 99 y=Find(y); 100 if(x != y) 101 fa[x]=y; 102 } 103 }_set; 104 void Solve() 105 { 106 for(int i=1;i <= n;++i)///将属于同一颗树的节点存在_set.fa[i]中 107 V[_set.Find(i)].push_back(i);///并查集查找i的祖先节点用Find() 108 _lca.Init(); 109 110 while(q--) 111 { 112 int u,v; 113 scanf("%d%d",&u,&v); 114 if(_set.Find(u) != _set.Find(v))///判断u,v是否属于同一棵树用Find() 115 puts("Not connected"); 116 else 117 { 118 int x=_lca.lca(u,v); 119 ll ans=_lca.dis[u]+_lca.dis[v]-2*_lca.dis[x]; 120 printf("%lld\n",ans); 121 } 122 } 123 } 124 void Init() 125 { 126 num=0; 127 for(int i=0;i <= n;++i) 128 { 129 head[i]=-1; 130 V[i].clear(); 131 } 132 _set.Init(); 133 } 134 int main() 135 { 136 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\C++WorkSpace\\in&&out\\contest","r",stdin); 137 while(~scanf("%d%d%d",&n,&m,&q)) 138 { 139 Init(); 140 for(int i=1;i <= m;++i) 141 { 142 int u,v,w; 143 scanf("%d%d%d",&u,&v,&w); 144 addEdge(u,v,w); 145 addEdge(v,u,w); 146 _set.Union(u,v); 147 } 148 Solve(); 149 } 150 return 0; 151 }