• F. Minimum Maximum Distance Codeforces Round 903 (Div. 3)


    Problem - F - Codeforces

    题目大意:有一棵n个点的树,其中有k个标记点,令点i到所有标记点的最远距离为fi,问所有点中fi的最小值是多少

    1<=k<=n<=2e5

    思路:我们首先考虑取得最小值的点在哪,我们假设这棵树是一条链,链上有两个标记点,如下图

    显然,在标记点2、4之间的点是才可能是取得最小值的点,因为如果在某一个点一段的话,这个最大值一定大于两个标记点之间的距离,而在中间的点一定都是小于这个距离的,那么在这两个点之间很显然最中间的点是取得最小值的点。

    所以取最小值的点一定在两个标记点的正中间,同时这两个标记点要距离最远,答案距离就是这个距离除以2向上取整

    要找两个距离最远的标记点,我们从任意一点i出发bfs找到一个最远的标记点j,这时有两种情况,一种就是这i,j就是距离最远的两个点,另一种情况是i在j和距离j更远的点k之间,

    如上图,从4出发找到最远的点2,但右边的5距离2更远,这时候因为2已经是最靠左的一个点了,所以只要再从2再跑一遍bfs,找到的最远的点和2一定是距离最远的两个点,类似于问以哪个标记点为根,能找到根到标记点的最远距离。

    1. //#include<__msvc_all_public_headers.hpp>
    2. #include
    3. using namespace std;
    4. typedef long long ll;
    5. const int N = 2e5 + 5;
    6. vectorint,int>>fac;
    7. int tot = 0;
    8. int n;
    9. int head[N];
    10. struct Edge
    11. {
    12. int v, next;
    13. }e[N*2];
    14. int mark[N];
    15. void addedge(int u, int v)
    16. {
    17. e[++tot].v = v;
    18. e[tot].next = head[u];
    19. head[u] = tot;
    20. }
    21. bool vis[N];
    22. void init()
    23. {
    24. for (int i = 1; i <= n; i++)
    25. {
    26. vis[i] = 0;
    27. head[i] = -1;
    28. mark[i] = 0;
    29. }
    30. }
    31. void solve()
    32. {
    33. int m;
    34. cin >> n;
    35. cin >> m;
    36. init();
    37. int it1 = -1;
    38. for (int i = 1; i <= m; i++)
    39. {
    40. int x;
    41. cin >> x;
    42. mark[x] = 1;
    43. if (it1 == -1)
    44. it1 = x;//任意找一个标记点作为起始根
    45. }
    46. for (int i = 1; i <= n - 1; i++)
    47. {
    48. int u, v;
    49. cin >> u >> v;
    50. addedge(u, v);
    51. addedge(v, u);
    52. }
    53. if (m == 1)
    54. {//如果只有1个标记点,那取最小值的点点就是那个标记点
    55. cout << 0 << '\n';
    56. return;
    57. }
    58. queueint, int>>q;
    59. q.push({ it1,0 });
    60. int ma = 0, mai;
    61. vis[it1] = 1;
    62. while (!q.empty())
    63. {//bfs找到距离根最远的点
    64. int u = q.front().first, nd = q.front().second;
    65. q.pop();
    66. for (int i = head[u]; ~i; i = e[i].next)
    67. {
    68. int v = e[i].v;
    69. if (vis[v])
    70. continue;
    71. vis[v] = 1;
    72. q.push({ v,nd + 1 });
    73. if (mark[v] && nd + 1 > ma)
    74. {
    75. ma = nd + 1, mai = v;
    76. }
    77. }
    78. }
    79. q.push({ mai,0 });//以之前找到的最远标记点为新根
    80. vis[mai] = 1;
    81. ma = 0, mai = -1;
    82. for (int i = 1; i <= n; i++)
    83. {
    84. vis[i] = 0;
    85. }
    86. while (!q.empty())
    87. {
    88. int u = q.front().first, nd = q.front().second;
    89. q.pop();
    90. for (int i = head[u]; ~i; i = e[i].next)
    91. {
    92. int v = e[i].v;
    93. if (vis[v])
    94. continue;
    95. vis[v] = 1;
    96. q.push({ v,nd + 1 });
    97. if (mark[v] && nd + 1 > ma)
    98. {
    99. ma = nd + 1, mai = v;
    100. }
    101. }
    102. }
    103. cout << (ma - 1) / 2 + 1;//答案就是最远距离/2
    104. cout << '\n';
    105. }
    106. int main()
    107. {
    108. std::ios::sync_with_stdio(false);
    109. std::cin.tie(0);
    110. //FILE* stream1;
    111. //freopen_s(&stream1, "in.txt", "r", stdin);
    112. //freopen_s(&stream1, "out.txt", "w", stdout);
    113. int t;
    114. cin >> t;
    115. while (t--)
    116. {
    117. solve();
    118. }
    119. return 0;
    120. }

  • 相关阅读:
    使用keil反汇编时的记录
    AI绘画部署及模型推荐和下载
    C语言使用MinGW中的GCC生成平面(flat)二进制文件
    LeetCode:117. 填充每个节点的下一个右侧节点指针 II(C++)
    OC-NSTread
    vue el-input 输入框输入不了
    BI工具-DataEase(1) 安装
    Basic Facilities of a Virtio Device (一)
    【Python】深究for循环迭代
    nginx网站服务
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/133886733