hdu 2586How far away ? 最近公共祖先LCA离线算法

There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.

题意:n个节点m条询问,问从x1节点到x2节点的最短距离。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxn 40005
#define LL long long
using namespace std;
struct node{
    int v,w;
};
vector<node>S[maxn];
vector<node>Q[maxn];
int visit[maxn],f[maxn],Rank[maxn],anc[maxn],ans[maxn],dis[maxn];
int n,m;
void init()
{
    for(int i=0;i<=n;i++)
    {
        S[i].clear(),Q[i].clear(),ans[i]=0,anc[i]=0,f[i]=i,Rank[i]=1,dis[i]=0;
    }
    memset(visit,0,sizeof(visit));
}
int Find(int u)
{
    if(f[u]!=u)
        f[u]=Find(f[u]);
    return f[u];
}
void Union(int u,int v)
{
    int f1,f2;
    f1=Find(u),f2=Find(v);
    if(f1!=f2)
    {
        if(Rank[f1]<Rank[f2])
        {
            f[f1]=f2;
            Rank[f2]+=Rank[f1];
        }
        else
        {
            f[f2]=f1;
            Rank[f1]+=Rank[f2];
        }
    }
}
void tarjan(int pos,int flow)
{
    anc[pos]=pos;
    dis[pos]=flow;
    for(int i=0;i<S[pos].size();i++)
    {
        int x=S[pos][i].v;
        if(!visit[x])
        {
            flow+=S[pos][i].w;
            tarjan(x,flow);
            Union(pos,x);
            anc[Find(x)]=pos;
        }
    }
    visit[pos]=1;
    for(int i=0;i<Q[pos].size();i++)
    {
        int x=Q[pos][i].v;
        int z=Q[pos][i].w;
        if(visit[x])
        {
            ans[z]=dis[pos]+dis[x]-2*dis[anc[Find(x)]];
        }
    }
}
int main()
{
    int T;
    cin>>T;
    int in[maxn];
    while(T--)
    {
        cin>>n>>m;
        init();
        memset(in,0,sizeof(in));
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            node tmp;
            cin>>x>>y>>z;
            tmp.v=y,tmp.w=z;
            S[x].push_back(tmp);
            in[y]++;//标记出根节点
            //tmp.v=x,tmp.w=z;
            //S[y].push_back(tmp);
            //in[x]++;
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;
            node tmp;
            cin>>x>>y;
            tmp.v=y,tmp.w=i;
            Q[x].push_back(tmp);
            tmp.v=x,tmp.w=i;
            Q[y].push_back(tmp);
        }
        for(int i=1;i<=n;i++)
        {
            if(in[i]==0)
            {
                //cout<<i<<endl;
                tarjan(i,0);
                break;
            }
        }
        for(int i=1;i<=m;i++)
        {
            cout<<ans[i]<<endl;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值