先考虑$k = 1$的情况,很明显每一条边都要被走两遍,而连成一个环之后,环上的每一条边都只要走一遍即可,所以我们使这个环的长度尽可能大,那么一棵树中最长的路径就是树的直径。

设直径的长度为$L$,答案就是$2(n - 1) - L + 1 = 2n - L - 1$。

考虑$k = 2$的情况,发现第一条边一定还是要把直径练成一个环,而第二条边是要再求一个类似于直径的东西,具体来说,可以把原来直径(记为$L_{1}$)上的每一条边的边权取为$-1$,然后再求一遍直径(记为$L_{2}$),这样子的话答案就是$2(n - 1) - (L_{1} - 1) - (L_{2} - 1) = 2n - L_{1} - L_{2}$。发现这样做之后如果第二条直径上包含着第一条直径上的部分,那么重叠的部分就被重新加了回来,所以这样子求出来的答案就是最后的答案。

由于可以在同一个点连边,那么$L_{2}$至少要为$0$。

注意第二次求直径的时候要使用树形$dp$,两次$bfs$的方法会挂,因为边带负权之后会相当于把之前带正权的边的贡献减掉,所以第一次求出来的一端并不一定是直径的一个端点。

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

Code:

#include <cstdio>
#include <cstring>
using namespace std; const int N = 1e5 + ;
const int inf = << ; int n, m, tot = , head[N];
int root, eid[N], dis[N], ans = ;
int f[N], d[N]; struct Edge {
int to, nxt, val;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].val = ;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} void dfs(int x, int fat) {
dis[x] = dis[fat] + ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
eid[y] = i ^ ;
dfs(y, x);
}
} void dfs2(int x, int fat) {
bool flag = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
flag = ;
dfs2(y, x);
chkMax(ans, d[y] + e[i].val + d[x]);
chkMax(d[x], d[y] + e[i].val);
}
if(!flag) d[x] = ;
} int main() {
read(n), read(m);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
} dis[] = -;
dfs(, );
dis[root = n + ] = -inf;
for(int i = ; i <= n; i++)
if(dis[i] > dis[root]) root = i; dfs(root, ); /* for(int i = 1; i <= n; i++)
printf("%d ", dis[i]);
printf("\n"); */ if(m == ) {
for(int i = ; i <= n; i++)
chkMax(ans, dis[i]);
printf("%d\n", * n - - ans);
return ;
} int pnt = n + ;
for(int i = ; i <= n; i++)
if(dis[pnt] < dis[i]) pnt = i; for(int x = pnt; x != root; x = e[eid[x]].to)
e[eid[x]].val = e[eid[x] ^ ].val = -; memset(f, , sizeof(f));
memset(d, , sizeof(d));
ans = ;
dfs2(root, ); printf("%d\n", * n - dis[pnt] - ans);
return ;
}

Luogu 3629 [APIO2010]巡逻的更多相关文章

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

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

  2. 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)

    本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打...一打打到第二天QAQ 首先什么边也不加时,总路程就是2*(n-1) 考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n ...

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

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

  4. [luogu P3628] [APIO2010]特别行动队

    [luogu P3628] [APIO2010]特别行动队 题目描述 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特 ...

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

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

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

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

  7. [APIO2010]巡逻(树的直径)

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

  8. luogu题解 P3629 【[APIO2010]巡逻】树的直径变式

    题目链接: https://www.luogu.org/problemnew/show/P3629 分析 最近被众多dalao暴虐,这道题傻逼地调了两天才知道错哪 不过这题比较良心给你一个容易发现性质 ...

  9. [Apio2010] 巡逻

    Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n). Ou ...

随机推荐

  1. 20165210 Java第二次实验报告

    20165210 实验二 Java面向对象程序设计 一.面向对象程序设计1--单元测试和TDD 实验要求 参考 http://www.cnblogs.com/rocedu/p/6371315.html ...

  2. (转)libcurl库使用方法,好长,好详细。

    一.ibcurl作为是一个多协议的便于客户端使用的URL传输库,基于C语言,提供C语言的API接口,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP ...

  3. SQL Sever 学习系列之三

    SQL Sever 学习系列之三 SQL Server 学习系列之一(薪酬方案+基础) SQL Server 学习系列之二(日期格式问题)         五.经理今天刚谈到with的用法(with的 ...

  4. Python collections系列之可命名元组

    可命名元组(namedtuple)  根据nametuple可以创建一个包含tuple所有功能以及其他功能的类 1.创建一个坐标类 import collections # 创建类, defaultd ...

  5. java文本文件读写

    java的IO系统中读写文件使用的是Reader和Writer两个抽象类,Reader中的read()和close()方法是抽象方法,Writer中的write().flush()和close()方法 ...

  6. Pix mesa 自动化测试

    最近在准备PIX的认证, 需要进行mesa测试. 但是Mesa的标准测试工具中没有针对PIX的TestCase, 只是提到NIST的web测试.路径为:http://pixpdqtests.nist. ...

  7. ASP.NET MVC5中View显示Html

    @Html.Raw(Model.Name) @(new HtmlString(Model.Name));

  8. POJ3421(质因数分解)

    X-factor Chains Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6501   Accepted: 2023 D ...

  9. SQLite连接C#笔记

    不得不吐槽,实在是太坑了.以下几点一定要注意: 要下载两个东西,都要上官网.一个是SQLite for Windows,一个是System.Data.SQLite. 下载下来的DLL里面有个test, ...

  10. PostgreSQL本地化

    从管理员的角度描述可用的本地化特性.PostgreSQL支持两种本地化方法:利用操作系统的区域(locale)特性,提供对区域相关的排序顺序.数字格式. 翻译过的信息和其它方面.提供一些不同的字符集来 ...