一、思路

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

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

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

二、代码

  1. #pragma comment(linker, "/STACK:1024000000,1024000000")
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<vector>
  6. using namespace std;
  7. const int INF = 0x3fff3fff;
  8. const int MAXN = 100010;
  9. typedef struct {
  10. int to, wt, next;
  11. } Edge;
  12. Edge tree[MAXN * 2];
  13. int head[MAXN], cnt;
  14. int n, m, q;
  15. /**office[i][j]:公司i的第j个办公室所在节点。*/
  16. vector<int> office[MAXN];
  17.  
  18. void add(int from, int to, int wt) {
  19. tree[cnt].to = to;
  20. tree[cnt].wt = wt;
  21. tree[cnt].next = head[from];
  22. head[from] = cnt++;
  23. }
  24.  
  25. void init() {
  26. memset(head, -1, sizeof(head));
  27. cnt = 0;
  28. for(int i = 0; i < MAXN; ++i)office[i].clear();
  29. }
  30.  
  31. /** deep[i]:i节点的深度。
  32. f[i]:i节点的父节点。
  33. len2f[i]:i节点到父节点的长度。
  34. */
  35. int deep[MAXN], f[MAXN], len2f[MAXN];
  36. /**
  37. d:深度。总根(树的重心)节点的深度为0。
  38. */
  39. void dfsDep(int root, int par, int d) {
  40. deep[root] = d;
  41. f[root] = par;
  42. for(int i = head[root], to = -1; i != -1; i = tree[i].next) {
  43. to = tree[i].to;
  44. if(to != par) {
  45. len2f[to] = tree[i].wt;
  46. dfsDep(to, root, d + 1);
  47. }
  48. }
  49. }
  50.  
  51. int getDis(int a, int b) {
  52. int res = 0;
  53. while(deep[a] < deep[b]) {
  54. res += len2f[b];
  55. b = f[b];
  56. }
  57. while(deep[a] > deep[b]) {
  58. res += len2f[a];
  59. a = f[a];
  60. }
  61. while(a != b) {
  62. res += len2f[a] + len2f[b];
  63. a = f[a];
  64. b = f[b];
  65. }
  66. return res;
  67. }
  68.  
  69. int main() {
  70. #ifndef ONLINE_JUDGE
  71. freopen("input.txt", "r", stdin);
  72. #endif // ONLINE_JUDGE
  73. int t, a, b, c;
  74. scanf("%d", &t);
  75. while(t--) {
  76. init();
  77. scanf("%d%d", &n, &m);
  78. for(int i = 1; i < n; ++i) {
  79. scanf("%d%d%d", &a, &b, &c);
  80. add(a, b, c);
  81. add(b, a, c);
  82. }
  83. for(int i = 1; i <= m; ++i) {
  84. scanf("%d", &a);
  85. for(int k = 0; k < a; ++k) {
  86. scanf("%d", &b);
  87. office[i].push_back(b);
  88. }
  89. }
  90.  
  91. dfsDep(1, -1, 0);
  92.  
  93. scanf("%d", &q);
  94. for(int i = 1; i <= q; ++i) {
  95. scanf("%d%d", &a, &b);
  96. c = INF;
  97. for(int j = 0, asz = office[a].size(); j < asz; ++j) {
  98. for(int k = 0, bsz = office[b].size(); k < bsz; ++k) {
  99. c = min(c, getDis(office[a][j], office[b][k]));
  100. if(c == 0) {j = asz; break;}
  101. }
  102. }
  103. printf("%d\n", c);
  104. }
  105. }
  106. return 0;
  107. }

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. Linux:centOS LAMP搭建之软件包下载地址

    MySQL5.1 wget mysql-5.1.73-linux-i686-glibc23.tar.gz #二进制包 MySQL5.6 wget http://mirrors.sohu.com/mys ...

  2. 微信小程序自定义tabbar的问题

    个人感觉小程序的tab样式自定义的能力有所欠缺,不够美观,于是今天自己diy了一个tab 测试的时候发现,无论是使用navigator跳转(会出现点击的效果)还是用bindtap(触摸),因为没有定义 ...

  3. Windows2012启动自动帐户登陆

    Win+R 启动 输入regedit  运行注册表 找到[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogo ...

  4. Django博客开发实践,初学者开发经验

    python,Django初学者,开发简易博客,做了一下笔记,记录了开发的过程,功力浅薄,仅供初学者互相 交流,欢迎意见建议.具体链接:Django博客开发实践(一)--分析需求并创建项目 地址:ht ...

  5. threejs 世界坐标与屏幕坐标相互转换

    屏幕坐标转世界坐标: let pX = (screenPoint.x / this.scene.renderer.domElement.clientWidth) * 2 - 1; let pY = - ...

  6. web.xml配置详解(2)

    1 定义头和根元素 部署描述符文件就像所有XML文件一样,必须以一个XML头开始.这个头声明可以使用的XML版本并给出文件的字符编码.DOCYTPE声明必须立即出现在此头之后.这个声明告诉服务器适用的 ...

  7. [LOJ6261]一个人的高三楼

    loj description 给你一个长度为\(n\)的数列\(a_i\),求它的\(k\)次前缀和模\(998244353\).(就是做\(k\)次前缀和后的数列) \(n\le10^5,k\le ...

  8. GridView合并表头多重表头

    后台代码: using System; using System.Data; using System.Configuration; using System.Web; using System.We ...

  9. POJ1220 Number Base Conversion

    题意 Write a program to convert numbers in one base to numbers in a second base. There are 62 differen ...

  10. Python 函数-max()

    max( x, y, z, .... )max() 方法返回给定参数的最大值,参数可以为序列.返回给定参数的最大值.x.y.z数值表达式. 实例 #!/usr/bin/python print &qu ...