HDU2874 Connections between cities(并查集+倍增LCA算法求森林最短路)
题意:
第一次世界大战后,许多城市遭到严重破坏,我们需要重建这些城市。但是,某些材料只能在某些地方生产。所以我们需要将这些材料从一个城市运到另一个城市。由于战争期间大部分道路已被完全摧毁,两个城市之间可能没有路径,也没有环存在。 现在,你的任务来了。在告诉您道路状况后,我们想知道任何两个城市之间是否存在路径。如果答案是肯定的,则输出它们之间的最短路径。
题解:
并查集判连通块,对每个连通块做一个倍增LCA处理,之后就是求LCA算带边权树的最短路~
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxn=1e5; int N,M,Q; int father[30][maxn]; int h[maxn]; ll d[maxn]; struct node { int u; int v; ll w; int next; }edge[maxn]; int head[maxn]; int tol; void addedge (int u,int v,ll w) { edge[tol].u=u; edge[tol].v=v; edge[tol].w=w; edge[tol].next=head[u]; head[u]=tol++; } int visit[maxn]; void dfs (int x,int u) { visit[x]=1; father[0][x]=u; for (int i=1;(1<<i)<=h[x];i++) father[i][x]=father[i-1][father[i-1][x]]; for (int i=head[x];i!=-1;i=edge[i].next) { int v=edge[i].v; if (v==father[0][x]) continue; h[v]=h[x]+1; d[v]=d[x]+edge[i].w; dfs(v,x); } } int lca (int x,int y) { if (h[x]>h[y]) swap(x,y); for (int i=20;i>=0;i--) if (h[x]<=h[y]-(1<<i)) y=father[i][y]; if (x==y) return x; for (int i=20;i>=0;i--) if (father[i][x]!=father[i][y]) { x=father[i][x]; y=father[i][y]; } return father[0][x]; } ll getDis (int x,int y) { return d[x]+d[y]-2*d[lca(x,y)]; } int f[maxn]; int findfather (int x) { int a=x; while (x!=f[x]) x=f[x]; while (a!=f[a]) { int z=a; a=f[a]; f[z]=x; } return x; } void Union (int a,int b) { int faA=findfather(a); int faB=findfather(b); if (faA!=faB) f[faA]=faB; } int main () { while (~scanf("%d%d%d",&N,&M,&Q)) { memset(father,0,sizeof(father)); memset(h,0,sizeof(h)); memset(d,0,sizeof(d)); memset(head,-1,sizeof(head)); memset(visit,0,sizeof(visit)); tol=0; for (int i=1;i<=N;i++) f[i]=i; for (int i=0;i<M;i++) { int u,v;ll w; scanf("%d%d%lld",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); Union(u,v); } for (int i=1;i<=N;i++) if (!visit[i]) dfs(i,i); for (int i=0;i<Q;i++) { int x,y; scanf("%d%d",&x,&y); if (findfather(x)!=findfather(y)) printf("Not connected\n"); else printf("%lld\n",getDis(x,y)); } } return 0; }