话说这是去年大爷的一道NOIP模拟赛题,对着大爷的代码看了一堂课的我终于把这题写掉了。

本题要求在基环树给定的环上删去一条边使剩下的树的直径最小,输出这个最小直径。

那么基环树可以画成这样子的:

有一些在环上的点,还有一些不在环上的点,显然只能在环上断边,我们预处理找出这个环$a_1 - a_m$,然后处理出环上的每一条边的权值$eVal_i$。

先考虑怎么找环,可以用一个栈记录一下系统栈中的元素,当再一次走到一个已经走过的结点的时候把栈里的元素一个一个弹出直到当前元素出栈为止,然后这些元素就是环上的点。

因为要在环上断边,不妨先断开$a_1$和$a_m$之间的边,然后我们预处理四个值$s0_i, s1_i, t0_i, t1_i$,$s0_i$表示从$a_1$开始在环上按照$1, 2, 3, ..., m$的顺序走走到边$a_i, a_{i + 1}$之前能走的最长路径,$s1_i$表示从$a_n$开始走$m, m -  1, m - 2, ..., 1$走到边$a_{i}, a_{i - 1}$之前能走到的最长路径,$t0_i$表示断开边$a_i, a_{i + 1}$$a_1$所在的联通块的直径,$t1_i$则表示断开边$a_{i}, a_{i - 1}$$a_n$所在的联通块的直径,这样子我们枚举一下环上的断边,用$max(t0_i, t1_{i + 1}, eVal_m + s0_i + s1_{i + 1})$更新答案即可。

考虑一下怎么计算$s$和$t$,我们依然可以预处理出从每一个环上的点($a_i = x$)开始不经过环上的点所能走到的最长链$fir_x$和直径$mx_i$,事实上,我们只要顺便计算一下次长链就可以算出直径,所以这些东西可以在一趟$dfs$里解决掉。

我们可以从小到大枚举$1-m$,然后记录一下环上走过的路径,然后顺便用沿路可能出现的最优解更新答案,其实$ans$的初值应该是$t0_m$所以在循环的时候应该注意在这趟循环中循环到$m$,要不然输出$0$……

$t$的计算方法同理。

然后就是码码码,感觉细节巨多。

时间复杂度$O(n)$。

Code:

  1. #include <cstdio>
  2. #include <cstring>
  3. using namespace std;
  4. typedef long long ll;
  5.  
  6. const int N = 2e5 + ;
  7.  
  8. int n, m = , tot = , head[N], a[N], top = , sta[N];
  9. ll fir[N], sec[N], mx[N], s0[N], s1[N], t0[N], t1[N], eVal[N];
  10. bool vis[N], in[N];
  11.  
  12. struct Edge {
  13. int to, nxt;
  14. ll val;
  15. } e[N << ];
  16.  
  17. inline void add(int from, int to, ll val) {
  18. e[++tot].to = to;
  19. e[tot].val = val;
  20. e[tot].nxt = head[from];
  21. head[from] = tot;
  22. }
  23.  
  24. template <typename T>
  25. inline void read(T &X) {
  26. X = ; char ch = ; T op = ;
  27. for(; ch > '' || ch < ''; ch = getchar())
  28. if(ch == '-') op = -;
  29. for(; ch >= '' && ch <= ''; ch = getchar())
  30. X = (X << ) + (X << ) + ch - ;
  31. X *= op;
  32. }
  33.  
  34. template <typename T>
  35. inline T max(T x, T y) {
  36. return x > y ? x : y;
  37. }
  38.  
  39. template <typename T>
  40. inline T min(T x, T y) {
  41. return x > y ? y : x;
  42. }
  43.  
  44. template <typename T>
  45. inline void chkMax(T &x, T y) {
  46. if(y > x) x = y;
  47. }
  48.  
  49. template <typename T>
  50. inline void chkMin(T &x, T y) {
  51. if(y < x) x = y;
  52. }
  53.  
  54. bool getCir(int x, int fat) {
  55. if(vis[x]) {
  56. for(; ; ) {
  57. int now = sta[top];
  58. in[now] = ;
  59. a[++m] = now;
  60. --top;
  61. if(now == x) return ;
  62. }
  63. }
  64.  
  65. vis[x] = ; sta[++top] = x;
  66. int tmp = top;
  67. for(int i = head[x]; i; i = e[i].nxt) {
  68. int y = e[i].to;
  69. if(y == fat) continue;
  70. if(getCir(y, x)) return ;
  71. top = tmp;
  72. }
  73.  
  74. return ;
  75. }
  76.  
  77. void getEval(int x, int to) {
  78. if(to == m + ) return;
  79. for(int i = head[x]; i; i = e[i].nxt) {
  80. int y = e[i].to;
  81. if(y != a[to + ]) continue;
  82. eVal[to] = e[i].val;
  83. getEval(y, to + );
  84. }
  85. }
  86.  
  87. ll getMx(int x, int fat) {
  88. ll res = 0LL;
  89. for(int i = head[x]; i; i = e[i].nxt) {
  90. int y = e[i].to;
  91. if(y == fat || in[y]) continue;
  92.  
  93. ll tmp = getMx(y, x), now = fir[y] + e[i].val;
  94.  
  95. chkMax(res, tmp);
  96. if(now > fir[x]) sec[x] = fir[x], fir[x] = now;
  97. else if(now > sec[x]) sec[x] = now;
  98. }
  99. chkMax(res, fir[x] + sec[x]);
  100. return res;
  101. }
  102.  
  103. int main() {
  104. // freopen("tube2.in", "r", stdin);
  105.  
  106. read(n);
  107. for(int i = ; i <= n; i++) {
  108. int x, y; ll v;
  109. read(x), read(y), read(v);
  110. add(x, y, v), add(y, x, v);
  111. }
  112.  
  113. getCir(, );
  114. a[m + ] = a[];
  115.  
  116. /* for(int i = 1; i <= m; i++)
  117. printf("%d ", a[i]);
  118. printf("\n"); */
  119.  
  120. getEval(a[], );
  121.  
  122. /* for(int i = 1; i <= m; i++)
  123. printf("%lld ", eVal[i]);
  124. printf("\n"); */
  125.  
  126. for(int i = ; i <= m; i++)
  127. mx[i] = getMx(a[i], );
  128.  
  129. /* for(int i = 1; i <= m; i++)
  130. printf("%lld ", mx[i]);
  131. printf("\n"); */
  132.  
  133. ll tmp = 0LL;
  134. for(int i = ; i < m; i++) {
  135. s0[i] = max(s0[i - ], tmp + fir[a[i]]);
  136. tmp += eVal[i];
  137. }
  138.  
  139. tmp = 0LL;
  140. for(int i = m; i > ; i--) {
  141. s1[i] = max(s1[i + ], tmp + fir[a[i]]);
  142. tmp += eVal[i - ];
  143. }
  144.  
  145. tmp = 0LL;
  146. for(int i = ; i <= m; i++) {
  147. t0[i] = max(t0[i - ], max(mx[i], tmp + fir[a[i]]));
  148. chkMax(tmp, fir[a[i]]);
  149. tmp += eVal[i];
  150. }
  151.  
  152. tmp = 0LL;
  153. for(int i = m; i > ; i--) {
  154. t1[i] = max(t1[i + ], max(mx[i], tmp + fir[a[i]]));
  155. chkMax(tmp, fir[a[i]]);
  156. tmp += eVal[i - ];
  157. }
  158.  
  159. /* printf("\n");
  160. for(int i = 1; i <= m; i++)
  161. printf("%lld ", s0[i]);
  162. printf("\n");
  163.  
  164. for(int i = 1; i <= m; i++)
  165. printf("%lld ", s1[i]);
  166. printf("\n");
  167.  
  168. for(int i = 1; i <= m; i++)
  169. printf("%lld ", t0[i]);
  170. printf("\n");
  171.  
  172. for(int i = 1; i <= m; i++)
  173. printf("%lld ", t1[i]);
  174. printf("\n"); */
  175.  
  176. ll ans = t0[m];
  177. for(int i = ; i < m; i++)
  178. chkMin(ans, max(max(t0[i], t1[i + ]), s0[i] + s1[i + ] + eVal[m]));
  179.  
  180. printf("%lld\n", ans);
  181. return ;
  182. }

CF835F Roads in the Kingdom的更多相关文章

  1. [NOI2013]快餐店 / CF835F Roads in the Kingdom (基环树)

    题意 一颗基环树,选一对点使得这两个点的最短距离最大. 题解 相当于找基环树的直径,但是这个直径不是最长链,是基环树上的最短距离. 然后不会做. 然后看了ljh_2000的博客. 然后会了. 这道题最 ...

  2. CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径

    传送门--CF 传送门--UOJ 题目要求基环树删掉环上的一条边得到的树的直径的最小值. 如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径. 对于环上的点, ...

  3. Codeforces 835 F. Roads in the Kingdom

    \(>Codeforces\space835 F. Roads in the Kingdom<\) 题目大意 : 给你一棵 \(n\) 个点构成的树基环树,你需要删掉一条环边,使其变成一颗 ...

  4. Codeforces 835 F Roads in the Kingdom(树形dp)

    F. Roads in the Kingdom(树形dp) 题意: 给一张n个点n条边的无向带权图 定义不便利度为所有点对最短距离中的最大值 求出删一条边之后,保证图还连通时不便利度的最小值 $n & ...

  5. codeforces 427 div.2 F. Roads in the Kingdom

    F. Roads in the Kingdom time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  6. Codeforces 835F Roads in the Kingdom (环套树 + DP)

    题目链接 Roads in the Kingdom 题意  给出一个环套树的结构,现在要删去这个结构中的一条边,满足所有点依然连通. 删边之后的这个结构是一棵树,求所有删边情况中树的直径的最小值. 显 ...

  7. 题解-CodeForces835F Roads in the Kingdom

    Problem CodeForces-835F 题意:求基环树删去环上任意一边后直径最小值,直径定义为所有点对最近距离的最大值 Solution 首先明确删去环上一点是不会影响树内直径的,所以应当先把 ...

  8. Codeforces 835F Roads in the Kingdom - 动态规划

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度. 路径可以分为两部分:跨过环 和 在树内 ...

  9. codeforces:Roads in the Kingdom分析和实现

    题目大意:国家有n个城市,还有n条道路,每条道路连通两个不同的城市,n条道路使得所有n个城市相互连通.现在国家经费不足,要关闭一条道路.国家的不便度定义为国家中任意两个不同的城市之间的距离的最大值,那 ...

随机推荐

  1. LeetCode Delete Operation for Two Strings

    原题链接在这里:https://leetcode.com/problems/delete-operation-for-two-strings/description/ 题目: Given two wo ...

  2. add-apt-repository 添加

     add-apt-repository 添加 需要安装的软件包 apt-get install python-software-properties 除此之外还要安装 software-propert ...

  3. Ubantu中安装sublime

    Sublime-text-3的安装步骤   添加Sublime-text-3软件包的软件源 sudo add-apt-repository ppa:webupd8team/sublime-text-3 ...

  4. Maven入门----MyEclipse创建maven项目(二)

    新建项目: Next next next 新建项目后,MyEclipse会自动从远程仓库中下载支持包,需要几分钟左右时间. 项目结构图: HelloWorld.java public class He ...

  5. sqldeveloper和plsqldebeloper

    sqldeveloper : 支持不用tns连,支持jdbc直接连的. plsqldebeloper : 必须使用tns连, 如果oracle安装在本机,本机已经有tns文件,和oci.dll,只需在 ...

  6. 蓝桥杯 算法训练 ALGO-34 纪念品分组

    算法训练 纪念品分组   时间限制:1.0s   内存限制:256.0MB 问题描述 元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作.为使得参加晚会的同学所获得的纪念品价值 相对均衡,他要把购 ...

  7. S3C2440开发环境搭建(Ubuntu)

    我的操作系统是 Ubuntu 1404.可以使用下面的命令查看系统的版本: cat /etc/issue 安装.配置.启动 ftp 服务 sudo apt-get install vsftpd  修改 ...

  8. a标签什么时候可以设置宽高

    行内元素(如a标签),在文档流中的时候因为是行内元素所以无法设置宽高:而当设置了绝对定位或者浮动,会生成块框(即变成块元素),所以就可以设置宽高了

  9. js处理数值和日期本地化

    js处理数值和日期本地化 const s = new Intl.NumberFormat('zh-cn'); s.format(111.111) // "111.111" cons ...

  10. 2014.8.27 CAD数据结构

    Rwy表中存放所有物理跑道,主键rwy_id,但没有跑道中心点坐标 rwy_direction表中存放所有所有逻辑跑道号,也没有跑道入口坐标.同一rwy_id对应有2条记录 rwy_cline_poi ...