hdu2586 (LCA-Tarjan+并查集)

本文介绍了一种高效解决树形结构中两点间距离查询的问题,通过使用并查集和深度优先搜索(DFS)算法,实现了快速查找任意两点间的最短路径长度。适用于大规模数据集,如村庄中房屋之间的距离查询。

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

How far away ?

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

水题。

#include<bits/stdc++.h>
using namespace std;
const int maxn=40010;
int cnt=0,n;
int vis[maxn];      //访问标记
int fat[maxn];      //存父亲结点
int tar[maxn];      //存最近公共祖先结点
int dis[maxn];      //到树顶点的距离
typedef struct node
{
    int v,w;
}node;
node e[maxn<<1];
vector<int>head[maxn<<1];

typedef struct que
{
    int u,v,ans;
}que;
que d[maxn<<1];
vector<int>query[maxn<<1];

void init()
{
    cnt=0;
    for(int i=0;i<(maxn<<1);i++) head[i].clear();
    for(int i=0;i<(maxn<<1);i++) query[i].clear();
    for(int i=0;i<maxn;i++) fat[i]=i;
    memset(vis,0,sizeof(vis));
    memset(tar,0,sizeof(tar));
    memset(dis,0,sizeof(dis));
}
void add(int a,int b,int c)
{
	e[cnt].v=b;
	e[cnt].w=c;
	head[a].push_back(cnt++);
	e[cnt].v=a;
	e[cnt].w=c;
	head[b].push_back(cnt++);
}

int fd(int x)
{
    int r=x;
    while(fat[r]!=r)
        r=fat[r];
    int i=x,j;
    while(i!=r)
    {
        j=fat[i];
        fat[i]=r;
        i=j;
    }
    return r;
}

void join(int u,int v)
{
    int fu=fd(u),fv=fd(v);
    if(fu!=fv)
        fat[fu]=fv;
}

void dfs_tree(int s)
{
    vis[s]=1;
    for(int i=0;i<head[s].size();i++)
    {
        if(!vis[e[head[s][i]].v])
        {
            dis[e[head[s][i]].v]=dis[s]+e[head[s][i]].w;
            dfs_tree(e[head[s][i]].v);
            join(e[head[s][i]].v,s);
            tar[e[head[s][i]].v]=1;
        }
    }
    for(int i=0;i<query[s].size();i++)
    {
        if(tar[d[query[s][i]].v])
        {
            d[query[s][i]].ans=fd(d[query[s][i]].v);
            if(query[s][i]%2==0)
                d[query[s][i]+1].ans=d[query[s][i]].ans;
            else
                d[query[s][i]-1].ans=d[query[s][i]].ans;
        }
    }
}
void dfs()
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs_tree(i);
        }
    }
}
int main()
{
    int t,m;
    int x,y,z;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=0; i<n-1; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        int a,b;
        int num=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            d[num].u=a,d[num].v=b;
            query[a].push_back(num++);
            d[num].u=b,d[num].v=a;
            query[b].push_back(num++);
        }
        dfs();
        for(int i=0;i<num;i++)
        {
            if(i%2==0)
            {
                int k=dis[d[i].u] + dis[d[i].v] - 2*dis[d[i].ans];
                printf("%d\n",k);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值