一、思路

这题“看似”比较难搞的一点是,一个节点上有多个办公室,这怎么求?其他的,求树中任意两个节点的距离(注意:没有最远或最最进这一说法,因为树上任意两个节点之间有且仅有一条路径。不然就有回路了,对吧。)都不是特别难的问题。

(1)如何找到任意两个公司之间的最短距离?没有很好的办法,只能暴力。记录每个公司的每个办公室所在节点,求指定两个公司A和B的最短距离时,枚举公司A的所有办公室所在节点,再枚举公司B的所有办公室所在节点,求出被枚举的节点之间的距离,然后,取最小的那一个输出。

(2)求树中任意两个节点的距离?我一开始用的是Tarjan求LCA的算法,然后,交上去TLE了两发。后来换了一种策略,记录每个节点的深度、它的父节点以及它到父节点之间的距离。求任意两个点的LCA的时候,采用谁深度大谁先上移的方法,然后移动过程中记录移动了多少距离,当两个点移动到一个点时,这个点就是他们的LCA,返回记录的距离即可。这样,可以避免求子节点到根节点的距离(即麻烦又要多写很多不必要的代码)。另外一点,要不要先求出树的重心来优化时间复杂度,我用第二种策略提交的第一份AC的代码,求了树重心,耗时:8595MS;后来直接把求重心的代码去掉,直接把1号节点当总根节点,耗时:8782MS,差不多。所以,我下面贴的代码就没求树的重心了,这样代码也简洁了好多,关键函数就只有一个:找到给定两个节点的LCA并返回它们之间的距离。

二、代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 0x3fff3fff;
const int MAXN = 100010;
typedef struct {
    int to, wt, next;
} Edge;
Edge tree[MAXN * 2];
int head[MAXN], cnt;
int n, m, q;
/**office[i][j]:公司i的第j个办公室所在节点。*/
vector<int> office[MAXN];

void add(int from, int to, int wt) {
    tree[cnt].to = to;
    tree[cnt].wt = wt;
    tree[cnt].next = head[from];
    head[from] = cnt++;
}

void init() {
    memset(head, -1, sizeof(head));
    cnt = 0;
    for(int i = 0; i < MAXN; ++i)office[i].clear();
}

/** deep[i]:i节点的深度。
    f[i]:i节点的父节点。
    len2f[i]:i节点到父节点的长度。
*/
int deep[MAXN], f[MAXN], len2f[MAXN];
/**
    d:深度。总根(树的重心)节点的深度为0。
*/
void dfsDep(int root, int par, int d) {
    deep[root] = d;
    f[root] = par;
    for(int i = head[root], to = -1; i != -1; i = tree[i].next) {
        to = tree[i].to;
        if(to != par) {
            len2f[to] = tree[i].wt;
            dfsDep(to, root, d + 1);
        }
    }
}

int getDis(int a, int b) {
    int res = 0;
    while(deep[a] < deep[b]) {
        res += len2f[b];
        b = f[b];
    }
    while(deep[a] > deep[b]) {
        res += len2f[a];
        a = f[a];
    }
    while(a != b) {
        res += len2f[a] + len2f[b];
        a = f[a];
        b = f[b];
    }
    return res;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int t, a, b, c;
    scanf("%d", &t);
    while(t--) {
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i < n; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c);
            add(b, a, c);
        }
        for(int i = 1; i <= m; ++i) {
            scanf("%d", &a);
            for(int k = 0; k < a; ++k) {
                scanf("%d", &b);
                office[i].push_back(b);
            }
        }

        dfsDep(1, -1, 0);

        scanf("%d", &q);
        for(int i = 1; i <= q; ++i) {
            scanf("%d%d", &a, &b);
            c = INF;
            for(int j = 0, asz = office[a].size(); j < asz; ++j) {
                for(int k = 0, bsz = office[b].size(); k < bsz; ++k) {
                    c = min(c, getDis(office[a][j], office[b][k]));
                    if(c == 0) {j = asz; break;}
                }
            }
            printf("%d\n", c);
        }
    }
    return 0;
}

2017百度之星初赛B-1002(HDU-6115)的更多相关文章

  1. 2014百度之星初赛第二场hdu 4831 Scenic Popularity

    Scenic Popularity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  2. 2019 年百度之星 初赛一 1002 Game

    传送门 Problem Description 度度熊在玩一个好玩的游戏.游戏的主人公站在一根数轴上,他可以在数轴上任意移动,对于每次移动,他可以选择往左或往右走一格或两格.现在他要依次完成 n 个任 ...

  3. HDU - 6112 2017百度之星初赛A 今夕何夕

    今夕何夕  Accepts: 1345  Submissions: 5533  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 32768/ ...

  4. HDU 6118 2017百度之星初赛B 度度熊的交易计划(费用流)

    度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  5. HDU 6119 2017百度之星初赛B 小小粉丝度度熊 (二分)

    小小粉丝度度熊 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  6. HDU - 6114 2017百度之星初赛B Chess

    Chess  Accepts: 1805  Submissions: 5738  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 32768 ...

  7. HDU - 6113 2017百度之星初赛A 度度熊的01世界

    度度熊的01世界  Accepts: 967  Submissions: 3064  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 327 ...

  8. 2017百度之星初赛A-1006(HDU-6113)

    思路:在图的外面包一圈'0'字符,然后dfs统计'0'字符的个数和'1'字符的个数.结果如下(num0表示0字符的个数,num1表示1字符的个数): num0 == 1 && num1 ...

  9. 2017"百度之星"程序设计大赛 - 初赛(A) [ hdu 6108 小C的倍数问题 ] [ hdu 6109 数据分割 ] [ hdu 6110 路径交 ] [ hdu 6112 今夕何夕 ] [ hdu 6113 度度熊的01世界 ]

    这套题体验极差. PROBLEM 1001 - 小C的倍数问题 题 OvO http://acm.hdu.edu.cn/showproblem.php?pid=6108 (2017"百度之星 ...

随机推荐

  1. 在一个机器上获取大量PublicKey后的私钥恢复方法

    渗透测试过程中,有时候会在某个未授权访问漏洞中获取authorized_keys文件,里面有大量账户用于免密登录的PublicKey,这个时候如何进行下一步渗透? 可以考虑rsa碰撞的方式,找到公用p ...

  2. Linux之VIM常用功能

    介绍:vim包含三种模式分别为 命令模式:浏览文件,临时更改vim的工作方式,对字符批量处理(也可进行配置) 插入模式:对文件内容进行编辑 退出模式:退出VIM操作 一.命令模式     1.调整vi ...

  3. 微信小程序之答题领券系统构建

    这个项目做了有一段时间了,客户需求反复更改,所以版本也是在不断迭代,下面简要说明一下这个系统的构建过程吧 系统功能: 1.基于商城系统开发的商品答题领券功能 2.首页商品列表页显示当前商品的答题状态 ...

  4. Shell 命令行求两个文件每行对比的相同内容

    Shell 命令行求两个文件每行对比的相同内容 遇到的一个实际问题是,2017年08月01日起,所有未经实名的域名,全部停止解析.而我手上有不少域名,其中很多都是没有实名的.但我不知道哪些实名了,哪些 ...

  5. [interview]螺旋队列问题

    摘要 本文主要讲解三种螺旋队列的实现方式和打印输出: 从中心往外端顺时针旋转,记为『外螺旋队列』 从左顶点开始,绕剩下的最大圈顺时针往内旋转,记为『内螺旋队列』 从左顶点开始,之字形旋转(只能同行同列 ...

  6. Android学习笔记之Activity详解

    1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...

  7. puremvc源码阅读

    1.mediator作为ui管理器,是设计成可以list多个notification 2.所有ui想要监听notification,都需要register到facade中 3.puremvc只负责消息 ...

  8. 数位DP新识

    简单题:HDU2089    HDU3652  HDU4734   HDU3555  POJ3252  HigoCoder1033(需要前导0,或者用方法4) 总结: 1,dfs(pos,state, ...

  9. vue中特殊特性

    key 预期:number | string key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes.如果不使用 key,Vue 会使用一种最大限度减少 ...

  10. Oracle DB备份恢复篇之丢失控制文件

    实验目的 本篇主要模拟控制文件丢失后,如何根据实际情况恢复数据库,才能使数据库尽可能不丢失数据. 实验环境 1)Linux系统环境 [oracle@DG1 ~]$ lsb_release -a LSB ...