题目链接

容易发现,当加一条边时,树上会形成一个环,这个环上的每个点都是只要走一次的,也就是说我们的答案减少了这个环上点的个数,要使答案最小,即要使环上的点最多,求出直径\(L\),则答案为\(2(n-1)-L+1\)。

当加两条边时,同样会形成一个新环,但这个新环可能和第一个环有交点,而这些交点仍是要走两次的,所以我们要让交点的个数尽可能小,所以,把原直径上的所有边权取反,代表若取了这条边,答案会增大那么多,然后再求一次树的直径\(L_1\),则答案为\(2(n-1)-L+1-L_1+1=2n-L-L_1\)。

注意,第二次求直径不能用两边\(DFS/BFS\)来求,因为树中有负权边,直接跑答案显然是错的,所以我们要用树形\(DP\)求直径。

  1. #include <cstdio>
  2. const int MAXN = 5000010;
  3. namespace IO{
  4. inline int read(){
  5. int s = 0, w = 1;
  6. char ch = getchar();
  7. while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
  8. while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
  9. return s * w;
  10. }
  11. }using namespace IO;
  12. namespace G{
  13. struct Edge{
  14. int next, to, dis;
  15. }e[MAXN << 1];
  16. int head[MAXN], num;
  17. inline void Add(int from, int to, int dis){
  18. e[++num].to = to;
  19. e[num].dis = dis;
  20. e[num].next = head[from];
  21. head[from] = num;
  22. }
  23. }using namespace G;
  24. int n, k, s, t;
  25. int a, b;
  26. int pre[MAXN];
  27. int Max = 0;
  28. inline int max(int a, int b){
  29. return a > b ? a : b;
  30. }
  31. void dfs(int u, int fa, int dep){
  32. if(dep > Max && fa) s = u, Max = dep;
  33. for(int i = head[u]; i; i = e[i].next)
  34. if(e[i].to != fa)
  35. dfs(e[i].to, u, dep + e[i].dis);
  36. }
  37. void DFS(int u, int fa, int dep){
  38. if(dep > Max) t = u, Max = dep;
  39. for(int i = head[u]; i; i = e[i].next)
  40. if(e[i].to != fa)
  41. pre[e[i].to] = u, DFS(e[i].to, u, dep + e[i].dis);
  42. }
  43. int d[MAXN], ans = -2147483647;
  44. void dp(int u, int fa){
  45. for(int i = head[u]; i; i = e[i].next)
  46. if(e[i].to != fa){
  47. dp(e[i].to, u);
  48. ans = max(ans, d[u] + d[e[i].to] + e[i].dis);
  49. d[u] = max(d[u], d[e[i].to] + e[i].dis);
  50. }
  51. }
  52. int main(){
  53. n = read(); k = read();
  54. for(int i = 1; i < n; ++i){
  55. a = read(); b = read();
  56. Add(a, b, 1); Add(b, a, 1);
  57. }
  58. Max = -2147483647; dfs(1, 0, 0);
  59. Max = -2147483647; DFS(s, 0, 0);
  60. if(k == 1){
  61. printf("%d\n", (n << 1) - 1 - Max);
  62. return 0;
  63. }
  64. int now = t;
  65. while(now != s){
  66. for(int i = head[now]; i; i = e[i].next)
  67. if(e[i].to == pre[now]){
  68. e[i].dis = -1;
  69. break;
  70. }
  71. now = pre[now];
  72. }
  73. dp(t, 0);
  74. printf("%d\n", (n << 1) - Max - ans);
  75. return 0;
  76. }

【洛谷 P3629】 [APIO2010]巡逻 (树的直径)的更多相关文章

  1. 洛谷 P3629 [APIO2010]巡逻 解题报告

    P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...

  2. 洛谷P3629 [APIO2010]巡逻(树的直径)

    如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\). 考虑\(k=1\)的情况,会发现如果我们新修建一个道路,那么就会有一段路程少走一遍.这时选择连接树的直径的两个端点显然是最优的. 难就 ...

  3. [洛谷P3629] [APIO2010]巡逻

    洛谷题目链接:[APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以 ...

  4. 洛谷 P3629 [APIO2010]巡逻

    题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...

  5. BZOJ1912或洛谷3629 [APIO2010]巡逻

    一道树的直径 BZOJ原题链接 洛谷原题链接 显然在原图上路线的总长为\(2(n-1)\). 添加第一条边时,显然会形成一个环,而这条环上的所有边全部只需要走一遍.所以为了使添加的边的贡献最大化,我们 ...

  6. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  7. 【BZOJ2830/洛谷3830】随机树(动态规划)

    [BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...

  8. 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925

    题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...

  9. 洛谷 [P3629] 巡逻

    树的直径 树的直径有两种求法 1.两遍 dfs 法, 便于输出具体方案,但是无法处理负权边 2.DP 法,代码量少,可以处理负权边 #include <iostream> #include ...

随机推荐

  1. 关闭 Identity 插入限制

    当为identity列插入时会报错: 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'xx'中的标识列指定显式值. 但在复制表数据时想带主键一起复制时,这时要设置IDEN ...

  2. 【Luogu P1935】[国家集训队]圈地计划

    题目 最近房地产商 GDOI (Group of Dumbbells Or Idiots) 从 NOI (Nuts Old Idiots) 手中得到了一块开发土地. 据了解,这块土地是一块矩形的区域, ...

  3. spring多个定时任务quartz配置

    spring多个定时任务quartz配置 <?xml version=”1.0″ encoding=”UTF-8″?> <beans xmlns=”http://www.spring ...

  4. Leetcode 675.为高尔夫比赛砍树

    为高尔夫比赛砍树 你被请来给一个要举办高尔夫比赛的树林砍树. 树林由一个非负的二维数组表示, 在这个数组中: 0 表示障碍,无法触碰到. 1 表示可以行走的地面. 比1大的数 表示一颗允许走过的树的高 ...

  5. deeplearning.ai课程学习(2)

    第二周:神经网络的编程基础(Basics of Neural Network programming) 1.逻辑回归的代价函数(Logistic Regression Cost Function) 逻 ...

  6. Gated Recurrent Unit (GRU)

                                   Gated Recurrent Unit (GRU) Outline                             Backgr ...

  7. python之*args和**kwargs参数,以及迭代器

    *args让函数可以接受不限制多个位置参数,**kwargs让函数可以接受不限制多个关键字参数,用法如图 2.迭代器总结

  8. POJ 3856 deltree(模拟)

    Description You have just run out of disk space and decided to delete some of your directories. Rati ...

  9. 文件名的查找——find

    查找文件!!! 命令格式:find [PATH] [option] [action] 一.参数1——与时间有关的参数 -atime.-ctime.-mtime -mtime n:在n天之前的“一天之内 ...

  10. ajax中用jsonp接收json数据

    最近在做查快递网页时遇到一个问题,调用的快递100的api,但是快递100api不允许跨域请求,就是用127.0.0.1发的请求会直接被拦截. 只是个简单的网页,不想自己做服务器转发,最后找到了一个y ...