Hdu 2586 How far away ?

题目链接


http://acm.hdu.edu.cn/showproblem.php?pid=2586
 题目是说给定一张图,知道n - 1条边让两点相连,但是不会有两条路让两点相连,那么就是一颗树。然后又给定m个询问,问a, b两点间最短距离。
 那么使用LCA求最短公共父节点即可,并且增加一个容器存放到树根的值,tarjan的时候增加一个转移值以报存其父节点离树根的距离。之后增加一个容器保存询问的顺序即可离线化处理询问。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define rep(i, s, t) for(int i = s;i <= t;i++)
#define rap(i, s, t) for(int i = s;i >= t;i--)
using namespace std;
int n, m;
const int M = 100004;
vector<int>tree[M];
vector<int>query[M];
vector<int>queid[M];
vector<int>worth[M];
bool vis[M];
int f[M];
int ancestor[M];
int dis[M];
int ans[M];
int findd(int x)
{
    return x == f[x]?f[x]:f[x] = findd(f[x]);
}
void uni(int x, int y)
{
    x = findd(x);
    y = findd(y);
    if(x != y)
        f[x] = y;
}
void init()
{
    rep(i, 0, n){
        vis[i] = false;
        tree[i].clear();
        query[i].clear();
        worth[i].clear();
        queid[i].clear();
        f[i] = i;
        dis[i] = 0;
        ans[i] = 0;
    }
}
void input_tree()
{
    rep(i, 1, n - 1){
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        tree[a].push_back(b);
        worth[a].push_back(c);
        tree[b].push_back(a);
        worth[b].push_back(c);
    }
}
void input_query()
{
    rep(i, 1, m)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        query[a].push_back(b);
        queid[a].push_back(i);
        query[b].push_back(a);
        queid[b].push_back(i);
    }
}
void tarjan(int x, int value)
{
    dis[x] = value;
    vis[x] = true;
    rep(i, 0, (int)tree[x].size() - 1){
        int v = tree[x][i];
        if(vis[v] == true)
            continue;
        tarjan(v, value + worth[x][i]);
        uni(x, v);
        ancestor[findd(x)] = x;
    }
    rep(i, 0, (int)query[x].size() - 1){
        int v = query[x][i];
        if(vis[v])
            ans[queid[x][i]] = dis[x] + dis[v] - 2 * dis[ancestor[findd(v)]];
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        init();
        input_tree();
        input_query();
        tarjan(1, 0);
        rep(i, 1, m)
            printf("%d\n", ans[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值