LCA离线模板(Tarjan)倍增模板 hdu2586

本文详细介绍了两种图遍历算法——Tarjan算法和倍增算法,用于解决寻找两点间距离的问题。通过具体实例展示了如何利用这两种算法求解特定场景下任意两点间的最短路径,并附带了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

How far away ?

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 17189    Accepted Submission(s): 6618


Problem Description
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.
 

Input
First line is a single integer T(T<=10), indicating the number of test cases.
  For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
  Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
 

Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
 

Sample Input
  
  
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
 

Sample Output
  
  
10 25 100 100
Tarjan:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50005;
const LL mod=1e9+7;
const int inf = 0x3f3f3f3f;
struct edg
{
    int v,w;
    edg(int a,int b)
    {
        v=a;
        w=b;
    }
};
struct node
{
    int x,i;
    node(int a,int b)
    {
        x=a;
        i=b;
    }
} ;
vector<edg>v[N];
vector<node>query[N];
int fa[N],dis[N],ans[N],LCA[N];
bool vis[N];
int n;
void Init()
{
    for(int i=1;i<=n;i++)
    {
        v[i].clear();
        query[i].clear();
        fa[i]=i;
        dis[i]=0;
        LCA[i]=-1;
        vis[i]=false;
    }
    return ;
}
int Find(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
    x=Find(x);
    y=Find(y);
    fa[y]=x;
    return ;
}
void Tarjan(int s,int f)
{
    dis[s]=f;
    vis[s]=true;
    int l=v[s].size();
    for(int i=0;i<l;i++)
    {
        int x=v[s][i].v;
        int w=v[s][i].w;
        if(vis[x])continue;
        Tarjan(x,f+w);
        Union(s,x);
    }
    l=query[s].size();
    for(int i=0;i<l;i++)
    {
        int x=query[s][i].x;
        int y=query[s][i].i;
        if(!vis[x])continue;
        LCA[y]=Find(x);
        ans[y]=dis[x]+dis[s]-2*dis[Find(x)];
    }
    return ;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int q,x,y,z;

        scanf("%d%d",&n,&q);
        Init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            v[x].push_back(edg(y,z));
            v[y].push_back(edg(x,z));
        }
        for(int i=0;i<q;i++)
        {
            scanf("%d%d",&x,&y);
            query[x].push_back(node(y,i));
            query[y].push_back(node(x,i));
        }
        Tarjan(1,0);//最近公共祖先在LCA数组里
        for(int i=0;i<q;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}
倍增:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50005;
const int inf = 0x3f3f3f3f;
struct edg
{
    int v,w,next;
}E[N*2];
int cnt,n;
int head[N];
int deep[N];
int in[N];
int dis[N];
int fa[N][31];
void add(int u,int v,int w)
{
    E[cnt].v=v;E[cnt].w=w;E[cnt].next=head[u];head[u]=cnt++;
    E[cnt].v=u;E[cnt].w=w;E[cnt].next=head[v];head[v]=cnt++;
}
void dfs(int u,int f,int dep,int dist)
{
    deep[u]=dep;
    dis[u]=dist;
    fa[u][0]=f;
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        int v=E[i].v;
        int w=E[i].w;
        if(!deep[v])
            dfs(v,u,dep+1,dist+w);
    }
    return ;
}
void Init()
{
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v)
{
    if(deep[u]<deep[v])
        u=u^v,v=u^v,u=u^v;
    int d=deep[u]-deep[v];
    for(int i=0;(1<<i)<=d;i++)
        if((1<<i)&d)
        u=fa[u][i];
    if(u==v)
        return u;
    for(int i=20;i>=0;i--)
        if(fa[u][i]!=fa[v][i])
        u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int q,x,y,z;
        scanf("%d%d",&n,&q);
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        memset(deep,0,sizeof(deep));
        dfs(1,-1,1,0);
        Init();
        while(q--)
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",dis[x]+dis[y]-2*dis[LCA(x,y)]);
        }
    }
    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值