【洛谷 P3629】 [APIO2010]巡逻 (树的直径)
容易发现,当加一条边时,树上会形成一个环,这个环上的每个点都是只要走一次的,也就是说我们的答案减少了这个环上点的个数,要使答案最小,即要使环上的点最多,求出直径\(L\),则答案为\(2(n-1)-L+1\)。
当加两条边时,同样会形成一个新环,但这个新环可能和第一个环有交点,而这些交点仍是要走两次的,所以我们要让交点的个数尽可能小,所以,把原直径上的所有边权取反,代表若取了这条边,答案会增大那么多,然后再求一次树的直径\(L_1\),则答案为\(2(n-1)-L+1-L_1+1=2n-L-L_1\)。
注意,第二次求直径不能用两边\(DFS/BFS\)来求,因为树中有负权边,直接跑答案显然是错的,所以我们要用树形\(DP\)求直径。
#include <cstdio>
const int MAXN = 5000010;
namespace IO{
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
}using namespace IO;
namespace G{
struct Edge{
int next, to, dis;
}e[MAXN << 1];
int head[MAXN], num;
inline void Add(int from, int to, int dis){
e[++num].to = to;
e[num].dis = dis;
e[num].next = head[from];
head[from] = num;
}
}using namespace G;
int n, k, s, t;
int a, b;
int pre[MAXN];
int Max = 0;
inline int max(int a, int b){
return a > b ? a : b;
}
void dfs(int u, int fa, int dep){
if(dep > Max && fa) s = u, Max = dep;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
dfs(e[i].to, u, dep + e[i].dis);
}
void DFS(int u, int fa, int dep){
if(dep > Max) t = u, Max = dep;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
pre[e[i].to] = u, DFS(e[i].to, u, dep + e[i].dis);
}
int d[MAXN], ans = -2147483647;
void dp(int u, int fa){
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa){
dp(e[i].to, u);
ans = max(ans, d[u] + d[e[i].to] + e[i].dis);
d[u] = max(d[u], d[e[i].to] + e[i].dis);
}
}
int main(){
n = read(); k = read();
for(int i = 1; i < n; ++i){
a = read(); b = read();
Add(a, b, 1); Add(b, a, 1);
}
Max = -2147483647; dfs(1, 0, 0);
Max = -2147483647; DFS(s, 0, 0);
if(k == 1){
printf("%d\n", (n << 1) - 1 - Max);
return 0;
}
int now = t;
while(now != s){
for(int i = head[now]; i; i = e[i].next)
if(e[i].to == pre[now]){
e[i].dis = -1;
break;
}
now = pre[now];
}
dp(t, 0);
printf("%d\n", (n << 1) - Max - ans);
return 0;
}
【洛谷 P3629】 [APIO2010]巡逻 (树的直径)的更多相关文章
- 洛谷 P3629 [APIO2010]巡逻 解题报告
P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...
- 洛谷P3629 [APIO2010]巡逻(树的直径)
如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\). 考虑\(k=1\)的情况,会发现如果我们新修建一个道路,那么就会有一段路程少走一遍.这时选择连接树的直径的两个端点显然是最优的. 难就 ...
- [洛谷P3629] [APIO2010]巡逻
洛谷题目链接:[APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以 ...
- 洛谷 P3629 [APIO2010]巡逻
题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...
- BZOJ1912或洛谷3629 [APIO2010]巡逻
一道树的直径 BZOJ原题链接 洛谷原题链接 显然在原图上路线的总长为\(2(n-1)\). 添加第一条边时,显然会形成一个环,而这条环上的所有边全部只需要走一遍.所以为了使添加的边的贡献最大化,我们 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 【BZOJ2830/洛谷3830】随机树(动态规划)
[BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...
- 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925
题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...
- 洛谷 [P3629] 巡逻
树的直径 树的直径有两种求法 1.两遍 dfs 法, 便于输出具体方案,但是无法处理负权边 2.DP 法,代码量少,可以处理负权边 #include <iostream> #include ...
随机推荐
- Python的文件输入输出,如何追加内容,读取内容,添加内容
python主要的文件打开的几种访问模式 模式可以为读模式('r').写模式('w')或追加模式('a'),当然还有rb.wb.ab.r+.w+.a+.rb+.wb+.ab+,然而实际从代码上我也没看 ...
- Java与C++进行系统间交互:Protocol Buffer
在一次项目中,因笔者负责的java端应用需要与公司C++系统进行交互,公司选定Protocol Buffer方案,故简单的了解一下 有需要的可以看一下其他作者的文章,了解一下Protobuf: htt ...
- Qt 报错LINK2019:无法解析的外部符号
这里用的都是Qt 自己的东西,但是还是抱错,所以怀疑是没有包含进去,尝试了清理项目,重新编译等,还是不行 用到一个最好的办法,就是把构建的文件夹整个删除,在重新编译就可以了 如图所示,把debug和r ...
- Ubuntu 常见错误及解决方法——长期不定时更新
1. 修复 /etc/sudoers 文件损坏导致不能使用 sudo 命令 这是之前错误地编辑了 /etc/sudoers 这个文件导致的,因此撤销编辑即可,但由于已经不能使用 sudo 命令,因此不 ...
- Tensorflow多线程输入数据处理框架
Tensorflow提供了一系列的对图像进行预处理的方法,但是复杂的预处理过程会减慢整个训练过程,所以,为了避免图像的预处理成为训练神经网络效率的瓶颈,Tensorflow提供了多线程处理输入数据的框 ...
- Java IO流-File类的使用示例-创建文件夹和文件的正确方法
当创建一个文件时,比如:E:\\test\\test.txt,此时若文件夹test不存在,那么直接创建文件会出错,故首先要判断文件夹是否存在,不存在的话要首先创建文件夹. public class F ...
- windows下自己常用的几个bat
1.samba映射盘符和解除 net use Z: "\\sambaserver ip\dir" "password" /user:"username ...
- 搭建Hadoop环境(一)
我用SecureCRT作为客户端,链接虚拟机做的服务器,我用的桥接,所以把主机的一个端口映射到虚拟机22端口上去,
- 更新协同开发工具SVN的链接的服务器地址
公司内的协同开发工具使用的SVN,因为换了个服务器需要重置SVN地址,一下子有点措手不及. 研究了下SVN的操作菜单,发现有一个功能“重新定位”,应该就是我要找的了,试了一下果真没错,记录下 第一步: ...
- div加了float后 四个特性
1.宽度变成0 2.左漂浮 或者右漂浮 3.后面的标签占据原来的位置 4对前面的div没有影响 他会浮动到前面div下面