• 题目链接:

    https://www.luogu.org/problemnew/show/P3629

  • 分析

    最近被众多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]巡逻】树的直径变式的更多相关文章

  1. luogu题解 P1099 【树网的核】树的直径变式+数据结构维护

    题目链接: https://www.luogu.org/problemnew/show/P1099 https://www.lydsy.com/JudgeOnline/problem.php?id=1 ...

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

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

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

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

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

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

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

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

  6. 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)

    1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1034  Solved: 562[Submit][St ...

  7. P3629 [APIO2010]巡逻

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

  8. 洛谷 P3629 [APIO2010]巡逻

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

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

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

随机推荐

  1. multiprocessing.Pool报pickling error

    multiprocessing.Pool报pickling error 现象 multiprocessing.Pool传递一个普通方法(不在class中定义的)时, 能正常工作. from multi ...

  2. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_19-CMS前端页面查询开发-页面原型-Table组件测试

    页面填充内容.用一个表格来显示内容 3.1.2.1 Element-UI介绍 本项目使用Element-UI来构建界面,Element是一套为开发者.设计师和产品经理准备的基于 Vue 2.0 的桌面 ...

  3. Spring事务管理3----声明式事务管理(1)

     声明式事务管理(1)基于    基于 tx/aop  这种事务管理相比编程式事务管理来说对业务层基本没有改动,通过  TransactionProxyFactoryBean 创建业务层的代理,通过A ...

  4. html5新增的语义化标签极其作用

    在html5中,新增了几个语义化标签:<article>.<section>.<aside>.<hgroup>. <header>,< ...

  5. windows下安装配置winpcap

    winpcap官网:http://www.winpcap.org/ 1.首先下载安装winpcap.exe,http://www.winpcap.org/install/default.htm 目的是 ...

  6. 在HTML5 中使用 kindeditor 的方法

    1.打开:http://kindeditor.net/ke4/examples/default.html 2.查看源代码,另存为 3.打开http://kindeditor.net/demo.php, ...

  7. python解析html

    *参考 推荐BeautifulSoup http://blog.csdn.net/abclixu123/article/details/38502993 http://www.cnblogs.com/ ...

  8. RHCE\RHCSA

    加油,老杨,所有的事情坚持到最后都是最好的,之所以现在觉得不好,是因为还没有坚持到最后,终于考过了,哈哈哈,下一个目标OCP

  9. 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用

    目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...

  10. [CF1010D]Mars Over_位运算性质

    Mars rover 题目链接:http://codeforces.com/problemset/problem/1010/D 数据范围:略. 题解: 因为每次只改一个,改完之后改回去,这个性质很重要 ...