luogu题解 P3629 【[APIO2010]巡逻】树的直径变式
题目链接:
分析
最近被众多dalao暴虐,这道题傻逼地调了两天才知道错哪
不过这题比较良心给你一个容易发现性质的图
不修路时
每条路走两次可知需要走\(2(N-1)\)步
\(K=1\)
送分给你,直接\(O(N)\)求直径,若直径长为\(L\),由于新加路还要走一步,少走了\(L-1\)步
\(K=2\)
如果还是用求直径的方法来求发现不太对,与原来直径重叠那部分又要多走一遍
,于是不妨把原来直径边权取反再求一边直径,若长为L',因为已经减去重叠部分还是少走\((L'-1)\)步,答案就为\(2(N-1)-L-L'\)
注意
好象直径取反后不能简单地用dfs求直径,因为在第一次找最远点时可能得到一个错误的答案,于是就用DP来求,顺便学了一下DP求直径
DP求树的直径
\(D[v_i]\)表示在以\(v_i\)为根子树内走到的最大深度
转移:\(v_1,v_2...v_k\)是\(v_i\)子树内节点 \(D[i]=max_{1<=j<=k}(D[v_j]+edge(v_i,v_j))\)
若\(v_a,v_b\)是\(v_x\)子树内两节点,树的直径可以看作由四部分组成:
\(D[v_a]+edge(v_a,v_x)+edge(v_x,v_b)+D[v_b]\)
具体看代码实现
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <map>
#include <queue>
#include <algorithm>
#define ri register int
#define ll long long
using namespace std;
const int maxn=100005;
const int inf=0x7fffffff;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;
return ;
}
int n,k;
struct Edge{
int ne,to,dis;
}edge[maxn<<2];
int num_edge=-1,h[maxn];
int s,t;
inline void add_edge(int f,int t){
edge[++num_edge].ne=h[f];
edge[num_edge].to=t;
edge[num_edge].dis=1;
h[f]=num_edge;
}
int mx=-inf,vis[maxn];
void dfs_1(int fa,int cur,int cnt){
for(ri i=h[cur];i!=-1;i=edge[i].ne){
if(edge[i].to!=fa){
dfs_1(cur,edge[i].to,cnt+1);
}
}
if(cnt>mx){
mx=cnt,t=cur;
}
return ;
}
int pre[maxn],dmet[maxn],tot=0,ex=0;
void dfs_2(int fa,int cur,int cnt){
for(ri i=h[cur];i!=-1;i=edge[i].ne){
if(edge[i].to!=fa){
dfs_2(cur,edge[i].to,cnt+1);
pre[edge[i].to]=cur;
}
}
if(cnt>mx){
mx=cnt,s=cur;
}
return ;
}
int diameter;
void dfs_3(int fa,int cur,int cnt){
if(cur==t){
diameter=cnt;
return ;
}
for(ri i=h[cur];i!=-1;i=edge[i].ne){
int v=edge[i].to;
if(vis[v]&&v!=fa){
dfs_3(cur,v,cnt+1);
edge[i].dis=-1;
edge[i^1].dis=-1;
}
}
return ;
}
int d[maxn];
void dp(int fa,int now){
for(ri i=h[now];i!=-1;i=edge[i].ne){
int v=edge[i].to;
if(v==fa)continue;
dp(now,v);
mx=max(mx,d[now]+d[v]+edge[i].dis);//上一次循环已更新一次d[now]
d[now]=max(d[now],d[v]+edge[i].dis);
}
return ;
}
int main(){
int x,y;
read(n),read(k);
memset(h,-1,sizeof(h));
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
memset(vis,0,sizeof(vis));
dfs_1(0,1,0);
mx=-inf;
dfs_2(0,t,0);
int tmp=s;
while(tmp!=t){
vis[tmp]=1;
dmet[++tot]=tmp;
tmp=pre[tmp];
}
dmet[++tot]=t,vis[t]=1;
dfs_3(0,s,0);
//cout<<s<<' '<<t<<' '<<diameter<<endl;
/*-------*/
if(k==2){
mx=0;
dp(0,1);
int diameter_2=mx;
//cout<<mx<<endl;
if(mx<0)diameter_2=0;
printf("%d\n",2*n-diameter-diameter_2);
}
else{
printf("%d\n",2*(n-1)-(diameter-1));
}
return 0;
}
luogu题解 P3629 【[APIO2010]巡逻】树的直径变式的更多相关文章
- luogu题解 P1099 【树网的核】树的直径变式+数据结构维护
题目链接: https://www.luogu.org/problemnew/show/P1099 https://www.lydsy.com/JudgeOnline/problem.php?id=1 ...
- 洛谷 P3629 [APIO2010]巡逻 解题报告
P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...
- 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925
题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...
- 洛谷P3629 [APIO2010]巡逻(树的直径)
如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\). 考虑\(k=1\)的情况,会发现如果我们新修建一个道路,那么就会有一段路程少走一遍.这时选择连接树的直径的两个端点显然是最优的. 难就 ...
- [洛谷P3629] [APIO2010]巡逻
洛谷题目链接:[APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以 ...
- 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)
1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1034 Solved: 562[Submit][St ...
- P3629 [APIO2010]巡逻
题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄.每条道 ...
- 洛谷 P3629 [APIO2010]巡逻
题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...
- 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)
本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打...一打打到第二天QAQ 首先什么边也不加时,总路程就是2*(n-1) 考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n ...
随机推荐
- Qt之编译MySQL数据库驱动(MSVC)
Qt之编译MySQL数据库驱动(MSVC) (2013-12-13 20:24:46) 转载▼ 标签: qt mysql qmysql qt编译mysql qt之msvc编译mysql 分类: Qt ...
- 亿级在线系统二三事-网络编程/RPC框架 原创: johntech 火丁笔记 今天
亿级在线系统二三事-网络编程/RPC框架 原创: johntech 火丁笔记 今天
- UML期末复习题——2.8:UML Design Class Diagram(DCD)
第八题:设计类图 重要概念: 1. 类图(Class Diagram): 类图是面向对象系统建模中最常用和最重要的图,是定义其它图的基础.类图主要是用来显示系统中的类.接口以及它们之间的静态结构和关系 ...
- 反射序列化字段的时候,需要添加[Datamember]不然会,忽略这个字段
反射序列化字段的时候,需要添加[Datamember]不然会,忽略这个字段
- JAVA 基础编程练习题44 【程序 44 偶数的素数和】
44 [程序 44 偶数的素数和] 题目:一个偶数总能表示为两个素数之和. package cskaoyan; public class cskaoyan44 { @org.junit.Test pu ...
- laravel 加载指定版本的mongodb
composer require jenssegers/mongodb:3.3 注意开启 php的mongodb的扩展 pecl install mongodb
- 设计模式七大原则(C++描述)
前言 最近在学习一些基本的设计模式,发现很多博客都是写了六个原则,但我认为有7个原则,并且我认为在编码中思想还是挺重要,所以写下一篇博客来总结下 之后有机会会写下一些设计模式的博客(咕咕咕...... ...
- pip install locustio报错
安装locust时, 执行pip install locustio时报错 ERROR: Cannot uninstall 'requests'. It is a distutils installed ...
- 热更新之lua框架设计
目前中大型游戏项目包含部分VR与AR项目,都需要热更新与在线修改Bug等功能实现,虽然Xlua等插件已经给出了关于C#与Lua语言之间的双向无缝调用实现,但是就热更新的架构却没有提出,这需要广大游戏公 ...
- UE4 RHI与条件式编译
RHI即RenderHardwareInterface, 即渲染硬件接口, 是UE为实现跨平台而实现的一套API. 每个RHI接口都为OpenGL, Vulkan, DX11等做了不同的实现. 在引擎 ...