如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\)。

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

难就难在\(k=2\)的时候,还是上面的思路,首先肯定连接两个叶子结点最优。假设我们连接的是\(x,y\)两个叶子结点,它们到直径的距离分别为\(dis[x],dis[y]\),并设直径上两点的距离为\(d[u,v]\),这里\(u,v\)分别为叶子结点所在链和直径的交点。

因此最后的答案会增加\(d[u,v]-dis[x]-dis[y]\)。要使答案最小,那么也就也是使得\(dis[x]+dis[y]-d[u,v]\)最大。脑补一下,就会发现这其实就是在所有直径上面的边权取反过后,树的最长链。

所以再求一次树的直径就好了。因为最后有负边权存在,通过\(dfs/bfs\)来求会出错。所以最后dp一次就好啦。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, k;
struct Edge{
int u, v, next, w;
}e[N << 1];
int head[N], tot;
void adde(int u, int v) {
e[tot].w = 1; e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
}
int vis[N], f[N], d[N], dp[N];
void dfs(int u, int fa) {
f[u] = fa;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v != fa) {
d[v] = d[u] + e[i].w;
dfs(v, u) ;
}
}
}
int mx, p, L;
void Get(int x) {
d[x] = mx = 0;
dfs(x, 0);
for(int i = 1; i <= n; i++)
if(d[i] > mx) mx = d[i], p = i;
}
int solve() {
Get(1);Get(p);
return mx;
}
void dfs2(int u, int fa) {
vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v == fa || !vis[v]) continue ;
e[i].w = e[i ^ 1].w = -1;
dfs2(v, u) ;
}
}
void Dp(int u, int fa) {
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v == fa) continue ;
Dp(v, u);
L = max(L, dp[u] + dp[v] + e[i].w) ;
dp[u] = max(dp[u], dp[v] + e[i].w) ;
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> k;
memset(head, -1, sizeof(head)) ;
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
adde(u, v); adde(v, u);
}
int l = solve() ;
int ans = 2 * (n - 1) - l + 1;
if(k == 2) {
int u = p;
while(u != 0) {
vis[u] = 1;
u = f[u];
}
dfs2(p, 0) ;
Dp(1, 0) ;
ans = ans - L + 1;
}
cout << ans ;
return 0;
}

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

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

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

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

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

  3. 洛谷 P3629 [APIO2010]巡逻

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

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

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

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

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

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

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

  7. 【洛谷 P3629】 [APIO2010]巡逻 (树的直径)

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

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

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

  9. 洛谷 [P3629] 巡逻

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

随机推荐

  1. Dubbo2.7.3入门

    2.7.X的Dubbo,包名不再是com.alibaba,而是org.apache 先看工程目录结构 一个公共api模块,一个SpringBoot项目充当Dubbo服务,一个SpringBoot项目充 ...

  2. 如何将Prometheus仪表板添加到Grafana

    Grafana是可视化的时间序列的基础设施和应用程序指标领先的图形和仪表盘构建的,但在许多其他领域,包括工业传感器,家庭自动化,天气和过程控制使用.它为您的团队和全世界提供了一种强大而优雅的方式来创建 ...

  3. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  4. tensorflow-笔记02

    TensorFlow扩展功能 自动求导.子图的执行.计算图控制流.队列/容器 1.TensorFlow自动求导 在深度学习乃至机器学习中,计算损失函数的梯度是最基本的需求,因此TensorFlow也原 ...

  5. go上传图片微信服务器<<临时素材

    type WxImage struct { Type string `json:"type"` MediaId string `json:"media_id"` ...

  6. Vue 公众号开发 (菜鸡前段的血泪史)

    首先vue-cli就不说了 接下来要说我们需要注意什么 公众号的每个页面都有一个title 所以我们在开发过程中 需要插件 安装vue-wechat-title 安装vue-js-sdk

  7. 【Oracle】获取SQL执行计划

    一.plsql developer工具F5         在sqldeveloper中选中sql按F5即可查看执行计划         

  8. 复制Linux虚拟机(VMware vSphere Client 工具)

    1.VMware vSphere Client 工具 登录,如下图          IP.用户名/密码均是物理机,登录完成界面: 2.选择一个复制的原虚拟机 A,点击左上角[文件]——导出——导出O ...

  9. python_三目运算

    首先确定三目运算的使用条件, if只有两个才能用三目  只有 if:else:    先写个if else的小例子: if push == "lpush": self.conn.l ...

  10. [UOJ #393]【NOI2018】归程

    题目大意:有一张$n$个点$m$条边的图,每个边有两个属性$a_i,b_i$.有$Q$个询问,每个询问给出$v,p$,表示所有边中$b_i\leqslant p$的边会被标记,在点$v$,可以通过不被 ...