poj1986Distance Queries(LCA)

题目大意:

其实就是给你一颗三叉树,让你求树上任意两点之间的最近距离

解题思路:

求各个点到树的根的距离,然后计算要查询的这些点的最近共组先。


如图所示,求4与2之间的距离的办法就是dis[4]+dis[2]-2dis[3];而3其实就是2与4的最近公共祖先了。

最近公共最先的求法————Tarjan算法:(自己百度吧。。。)

代码:

#include<stdio.h>
#define N 10000*8+10
struct node{
   int to,dis,next;
};
node edg[N];
int head[N],h;
void aeg(int a,int b,int d)
{
    edg[h].to=b;
    edg[h].dis=d;
    edg[h].next=head[a];
    head[a]=h++;
}
struct qnode{
   int lca;
   int to;
   int next;
};
int qhead[N];
qnode qedg[N];
void aqeg(int a,int b)
{
    qedg[h].to=b;
    qedg[h].next=qhead[a];
    qhead[a]=h++;
}
int p[N];
int findp(int x)
{
    int k,y=x;
    while(x!=p[x])x=p[x];
//    while(y!=p[y]){
//        k=y;y=p[y];p[k]=x;不能合并
//    }
    return x;
}
bool visit[N];
int  dis[N];
void LCA(int u,int w)
{
    p[u]=u;
    dis[u]=w;
    visit[u]=true;
    int i,v;
    for(i=head[u];i!=-1;i=edg[i].next)
    {
        v=edg[i].to;
        if(!visit[v])
        {
            LCA(v,dis[u]+edg[i].dis);
            p[v]=u;
        }
    }
    for(i=qhead[u];i!=-1;i=qedg[i].next)
    {
        v=qedg[i].to;
        if(visit[v])
        {
            qedg[i].lca=findp(v);
            qedg[i^1].lca=qedg[i].lca;
        }
    }
}
void init(int n)
{
    int i;
    for(i=0;i<n+10;i++)
    {
        p[i]=i;
        dis[i]=0;
    }
    for(i=0;i<N;i++)
        head[i]=qhead[i]=-1;
}
int main()
{
    int u,v,d,n,m,i;
    char buf[10];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init(n);
        h=0;
        while(m--)
        {
            scanf("%d%d%d%s",&u,&v,&d,buf);
            aeg(u,v,d);
            aeg(v,u,d);
        }
        scanf("%d",&m);
        h=0;
        n=m;
        while(m--)
        {
            scanf("%d%d",&u,&v);
            aqeg(u,v);
            aqeg(v,u);
        }
        LCA(1,0);
//        for(i=1;i<=n;i++)
//            printf("%d ",dis[i]);
        int lca;
        for(i=0;i<n*2;i++){
        u=qedg[i].to;v=qedg[i+1].to;lca=qedg[i].lca;
        i++;
//      printf("%d %d %d\n",u,v,lca);
        d=dis[u]+dis[v]-2*dis[lca];
        printf("%d\n",d);
        }
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值