codevs1036 商务旅行

41 篇文章 0 订阅
1 篇文章 0 订阅

题目描述 Description

某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

输出描述 Output Description

在输出文件中输出该商人旅行的最短时间。

样例输入 Sample Input

5
1 2
1 5
3 5
4 5
4
1
3
2
5

样例输出 Sample Output

7

树上的最短路径,边权还是1……,lca模板题,虽然看数据需要倍增下,其实暴力lca也能过= =,代码打得比较随意233。
代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sz = 200010;
int head[sz],nxt[sz],dis[sz][22],par[sz][22],deep[sz],tot = 1,n,m,num[sz],l[sz];
int read()
{
    int x = 0 , f = 1;
    char in = getchar();
    while(in < '0' || in > '9')
    {
        if(in == '-')
            f = -1;
        in = getchar();
    }
    while('0' <= in && in <= '9')
    {
        x = (x << 3) + (x << 1) + in - '0';
        in = getchar();
    }
    return x * f;
}
void build_edge(int f,int t)
{
    l[tot] = t;
    nxt[tot] = head[f];
    head[f] = tot ++;
}
void dfs(int u,int fa,int dep)
{
    dis[u][0] = 1;
    par[u][0] = fa;
    deep[u] = dep;
    for(int i = head[u] ; i ; i = nxt[i])
        if(l[i] != fa)
            dfs(l[i],u,dep+1);
}
int lca(int u,int v)
{
    int ans = 0;
    if(deep[u] < deep[v])
        swap(u,v);
    for(int i = 21 ; i >= 0 ; i --)
        if(deep[par[u][i]] >= deep[v])
            ans += dis[u][i] , u = par[u][i];
    for(int i = 21 ; i >= 0 ; i --)
        if(par[u][i] != par[v][i])
            ans += dis[u][i] + dis[v][i] , u = par[u][i] , v = par[v][i];
    if(u != v)
        ans += 2;
    return ans;
}
void start_work()
{
    n = read();
    for(int i = 1 ; i < n ; i ++)
    {
        int u = read() , v = read();
        build_edge(u,v);
        build_edge(v,u);
    }
    m = read();
    for(int i = 1 ; i <= m ; i ++)
        num[i] = read();
    dfs(1,0,1);
    for(int j = 1 ; j <= 21 ; j ++)
        for(int i = 1 ; i <= n ; i ++)
            par[i][j] = par[par[i][j-1]][j-1],
            dis[i][j] = dis[i][j-1] + dis[par[i][j-1]][j-1];
}
void nidaoshidonga_jpg()
{
    int ans = 0;
    for(int i = 2 ; i <= m ; i ++)
        ans += lca(num[i],num[i-1]);
    printf("%d\n",ans);
}
int main()
{
    start_work();
    nidaoshidonga_jpg();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值