题目传送门

我们先来介绍一个概念:树的直径。

树的直径:树中最远的两个节点间的距离。(树的最长链)
树的直径有两种方法,都是$O(N)$。

第一种:两遍bfs/dfs(这里写的是两遍bfs)

从任意一个节点出发,遍历一遍树找到与出发点距离最远的点p。

再从节点p出发,遍历一遍求出与p距离最远的点q。则pq即为直径(其中一个)

但是不能处理负权边。

int bfs(int x)
{
queue<int>q;
memset(d,0x3f,sizeof(d));
memset(pre,,sizeof(pre));
fake=d[];
q.push(x);d[x]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(d[v]==fake) q.push(v),pre[v]=i,d[v]=d[u]+;
}
}
int top=x;
for(int i=;i<=n;i++)
if(d[i]>d[top]) top=i;
return top;
}
int get_d()
{
p=bfs();
p=bfs(p);
return d[p];
}

第二种:树形dp

void Treedp(int u)
{
vis[u]=;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v]) continue;
Treedp(v);
ans=max(ans,f[x]+f[y]+edge[i].val)
f[x]=max(f[x],f[y]+edge[i].val);
}
}

题目大意:给你一棵树,你需要把这棵树上的每条边至少遍历一次,走过一条边的代价是1,现在你可以添加1或2条边,新添的边可且仅可遍历一次,问最小代价是多少。

不加边的时候,答案就是$2*(n-1)$。

加一条新道路后,因为新道路必须经过恰好一次,设$l$,$r$为新建道路的两端,那么从$l$去$r$的时候走新道路,回来的时候走原来的道路。形成了一个环,也就是说其他与$l$,$r$无关的点还是走过两次,而连接$l$,$r$的路径上的边走一次就行了。而我们贪心的选择树中最长的路径,那就是树的直径。设直径为$d$,那么答案就是$2*(n-1)-d+1$。(+1是新建的那条道路)

加两条新道路后,也会形成一个环,但是我们不知道这个环与之前的那个环是不是有重叠关系。若重叠,那么两个环重叠的部分就不会被经过;不重叠还好说。那么我们如何解决?处理重叠情况,我们的目标是使重叠部分恰好经过两次,那么我们可以把第一次的直径上的所有边取反(1变成-1),再在取反了的树上找直径。最终答案就是

$2*(n-1)-(l1-1)-(l2-1)$。

Code

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define maxn 100090 using namespace std; int n,k,tot=,fake,p,ans1,ans2;
int head[maxn],d[maxn],pre[maxn],vis[maxn],f[maxn];
struct node{
int to,next,val;
}edge[maxn*]; void add(int x,int y)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
edge[tot].val=;
} int bfs(int s)
{
queue<int>q;
memset(pre,,sizeof(pre));
memset(d,0x3f,sizeof(d));
fake=d[];
q.push(s);d[s]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(d[v]==fake) d[v]=d[u]+edge[i].val,pre[v]=i,q.push(v);
}
}
int top=s;
for(int i=;i<=n;i++) if(d[i]>d[top]) top=i;
return top;
} void get_d()
{
p=bfs();
p=bfs(p);
} void Treedp(int u)
{
vis[u]=;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v]) continue;
Treedp(v);
ans2=max(ans2,f[u]+f[v]+edge[i].val);
f[u]=max(f[u],f[v]+edge[i].val);
}
} int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n-;i++)
{
int x=,y=;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
get_d();
ans1=d[p];
if(k==){printf("%d",*(n-)-d[p]+);return ;}
for(int i=pre[p];i;i=pre[edge[i^].to])
edge[i].val=-,edge[i^].val=-;
Treedp();
printf("%d",*(n-)-(ans1-)-(ans2-));
return ;
}

树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925的更多相关文章

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

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

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

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

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

    (这道题考察了求直径的两种方法......) 在原图中,每条边要经过两次,增加1条后,形成了一个环,那么环上的边只需要经过一次了(大量画图分析得),再增加一条又会形成一个环,如果这两个环有重叠,重叠部 ...

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

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

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

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

  6. P3629 [APIO2010]巡逻

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

  7. 洛谷 P3629 [APIO2010]巡逻

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

  8. Luogu 3629 [APIO2010]巡逻

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

  9. 【题解】P3629 [APIO2010]巡逻

    link 题意 有 \(n\) 个村庄,编号为 \(1, 2, ..., n\) .有 \(n – 1\) 条道路连接着这些村 庄,从任何一个村庄都可以到达其他任一个村庄.道路长度均为 1. 巡警车每 ...

随机推荐

  1. 【转载】一致性哈希算法(consistent hashing)

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...

  2. ansible 基本命令学习与踩坑

    1. 命令行参数 -v,–verbose 详细模式,如果命令执行成功,输出详细的结果(-vv –vvv -vvvv) -i PATH,–inventory=PATH 指定host文件的路径,默认是在/ ...

  3. Metasploit学习笔记之——情报搜集

    1.情报搜集 1.1外围信息搜索 1.1.1通过DNS和IP地址挖掘目标网络信息 (1)whois域名注冊信息查询(BT5.kali专有):root@kali:~# whois testfire.ne ...

  4. bzoj 1088 简单dfs

    /* 题意:给你一列仅仅能取0和1的数. 限制:每3个相邻的数的值固定,开头和结尾仅仅限制两个数 求:有多少种组合方案 解:搜索,在开头和结尾再加一个仅仅能取零的数,直接推断是否符合条件就可以 */ ...

  5. JavaScript随机数区间限制

    在一段区间内的取某个数字 有一个通用的方法 主要使用了一下两个javascript函数 1.Math.floor() 方法可对一个数进行下舍入 2.Math.random() 方法可返回介于 0 ~ ...

  6. http权威指南(一)-Http概述

    Http概述 在Web中,不管是浏览器还是server都是通过Http相互通信的.那么Http是怎样工作的呢? 首先,client向server发送Http请求,server会在Http响应中回送所请 ...

  7. sanic官方文档解析之Exception和Middleware,Listeners

    1,异常 异常是从处理请求内部抛出来的,并且通过Sanic自动的被处理异常,,异常用第一个参数携带异常信息,还可以接受在HTTP响应中要传递回的状态代码.引发异常 1.1引发异常 自动触发异常,,简单 ...

  8. CH 5105 Cookies(贪心+DP)

    \(CH 5105 Cookies\) \(solution:\) 真是好题一道!这道题我想了很久很久,就得这一题可以直接完全贪心,可惜最后还是失败了,但是对贪心的深入思考也换来了一个最优解方案.然后 ...

  9. React通用后台管理系统

    react-admin 部分采用了antd,相关功能较全,添加了较多的组件模块.star 664 GitHub:https://github.com/yezihaohao/react-admin 在线 ...

  10. 20170223-问题001,增强中的E消息 显示为 S模式消息,

     MM01 的屏幕增强,里面写的      MESSAGE e056(z1) WITH '供应链计划(SCP) 储备物料与当期物料不能同时选择.'.可是现实出来是S 消息模式,这是为什么?系统转换了吗 ...