LCA-并查集+tarjan-poj2874

要先加距离再回溯,多组数据是真的坑。
题意:给你N个点、M条无向边以及边的长度,可能这些点和边构成的不是一棵树,而是森林。然后给出Q次查询,查询两个节点间的最短距离。

#include<stdio.h>
#include<stdlib.h>
struct node{
    int to,next,w;
}a[20010];
struct node1{
    int to,next,ans;
}b[2000010];
int top,jl[10010],begin[10010],wenti[10010];
int fa[10010],p[10010],pd[10010],bh[10010];
void add(int x,int y,int w){
    a[++top].to=y;
    a[top].w=w;
    a[top].next=begin[x];
    begin[x]=top;
    return;
}
int findfa(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=findfa(fa[x]);
}
void findans(int x,int y,int k){
    int lca=findfa(y);
    b[k].ans=jl[x] + jl[y] - 2*jl[lca];
    return;
}
void dfs(int d){

    p[d]=1;
    fa[d]=d;
    int h=wenti[d];
    while(h){
        if(fa[b[h].to]==b[h].to){
            b[h].ans=jl[d] - jl[b[h].to];
        } 
        else if(fa[b[h].to]!=0){
            findans(d,b[h].to,h);
        }
        h=b[h].next;
    }
    h=begin[d];
    while(h){
        if(! p[a[h].to]){
            dfs(a[h].to);
            fa[a[h].to]=d;
        }
        h=a[h].next;
    }
    return;
}
void dfs1(int d){
    bh[d]=top;
    int h=begin[d];
    while(h){
        if(bh[a[h].to]==0){
            jl[a[h].to]=jl[d]+a[h].w;
            dfs1(a[h].to);
        }
        h=a[h].next;
    }
    return;
}
int main(){
    int n,m,x,y,w,i,j,k;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        for(i=1;i<=10000;i++){
            begin[i]=0;
            wenti[i]=0;
            bh[i]=0;
            pd[i]=0;
            p[i]=0;
            jl[i]=0;
            fa[i]=0;
        }
        top=0;
        for(i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&w);
            add(x,y,w);
            add(y,x,w);
        }
        top=0;
        for(i=1;i<=n;i++){
            if(bh[i]==0){
                top++;
                dfs1(i);
            }
        }
        top=0;
        for(i=1;i<=k;i++){
            scanf("%d%d",&x,&y);
            if(x==y){
                b[++top].ans=0;
                b[++top].ans=-2;
            }
            else if(bh[x]!=bh[y]){
                b[++top].ans=-1;
                b[++top].ans=-2;
            }

            else {
                b[++top].to=y;
                b[top].ans=-2;
                b[top].next=wenti[x];
                wenti[x]=top;
                b[++top].to=x;
                b[top].ans=-2;
                b[top].next=wenti[y];
                wenti[y]=top;
            }
        }
        for(i=1;i<=n;i++){
            if(pd[bh[i]]==0){
                dfs(i);
                pd[bh[i]]=1;
            }
        }
        for(i=1;i<=2*k;i++){
            if(b[i].ans==-2)
                continue;
            if(b[i].ans==-1)
                printf("Not connected\n");
            else 
                printf("%d\n",b[i].ans);
        }
    }

    return 0;
}
/*
5 3 3
1 3 2
2 4 3
5 2 3
1 4
4 5
1 1
*/ 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值