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;
}

 

posted @ 2020-03-19 20:02  zlc0405  阅读(137)  评论(0编辑  收藏  举报