题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)
本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打。。。一打打到第二天QAQ
首先什么边也不加时,总路程就是2*(n-1)
考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n-直径-1,如果能加一条边的话,因为希望减少的尽可能多,那么只需要把直径的首尾接起来,就不需要来回走,加一就是加了这一条新加入的边。
而k=2的时候,首先还是往最长链上面思考。然而做k=1的时候已经用掉了一段,我们需要k=2的和k=1的不重叠。
于是乎,我们跑完直径后之后把直径上的边权全部修改为-1,再跑一遍直径就可以了。那权值为-1的边又被选了就是考虑第一次算这条边的时候加了1,第二次的时候是-1,相当于是这条边没有产生任何贡献。所以最后答案是2(n-1)-(直径1-1)-(直径2-1)=2n-直径1-直径2
哪位大佬能教教我DP记路径吗。。。。感激不尽( ⊙ o ⊙ )啊!
我的傻乎乎的代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define R register int
using namespace std;
const int N=,Inf=0x3f3f3f3f;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
int n,k,mx,mx1,cnt,st,ed;
int pre[N],fir[N],cnte[N],d[N];
struct edge{
int v,w,nxt;
#define v(i) e[i].v
#define w(i) e[i].w
#define nxt(i) e[i].nxt
}e[N<<];
inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
namespace _dp {
void dp(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
dp(v,u);
mx=max(mx,d[u]+d[v]+w(i));
d[u]=max(d[u],d[v]+w(i));
}
}
inline void solve() {
memset(d,,sizeof(d));
dp(,);
}
}
inline void dfs(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
d[v]=d[u]+w(i);
dfs(v,u);
}
}
inline void solve() {
memset(d,0x3f,sizeof(d));
d[]=; dfs(,); mx=-Inf; st=,ed=;
for(R i=;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=)
mx=d[i],st=i;
memset(d,0x3f,sizeof(d));
d[st]=,dfs(st,); mx=-Inf;
for(R i=;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=st)
mx=d[i],ed=i;
}
inline void fd_p(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
fd_p(v,u);
pre[v]=u;
cnte[v]=i;
}
}
signed main() {
n=g(),k=g();
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v,),add(v,u,);
solve();
if(k==) {printf("%d\n",*n-mx-); return ;}
fd_p(st,); mx1=mx; pre[st]=;
for(R i=ed;i;i=pre[i]) if(cnte[i]&) w(cnte[i])=-,w(cnte[i]+)=-; else w(cnte[i])=-,w(cnte[i]-)=-;
mx=;
_dp::solve();
printf("%d\n",*n-mx1-mx);
}
我看不懂的代码(fromljh2000%%%%%)
#include<cstdio>
#include<iostream>
#include<cstring>
#define R register int
using namespace std;
const int N=;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
int n,k,cnt,anss,ans,rt,S,SP;
int fir[N],nxt[N],nxte[N],f[N][];
struct edge{
int v,w,nxt;
#define v(i) e[i].v
#define w(i) e[i].w
#define nxt(i) e[i].nxt
}e[N<<];
inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
inline void dfs(int u,int fa) {
R crt,s=,sp=;
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
dfs(v,u);
crt=f[v][]+w(i);
if(crt>f[u][]) s=nxt[u],sp=nxte[u],f[u][]=f[u][],f[u][]=crt,nxt[u]=v,nxte[u]=i;
else if(crt>f[u][]) f[u][]=crt,s=v,sp=i;
}
if(f[u][]+f[u][]>ans) {
ans=f[u][]+f[u][]; rt=u,S=s,SP=sp;
}
}
signed main() {
n=g(),k=g(); R x;
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v,),add(v,u,);
dfs(,);
anss=*(n-)-ans+;
if(k==) {printf("%d\n",anss); return ;}
if(f[rt][]>) {
x=S; w(SP)=-;
while(nxt[x]) w(nxte[x])=-,x=nxt[x];
}
x=rt;
while(nxt[x]) w(nxte[x])=-,x=nxt[x];
ans=; memset(f,,sizeof(f));
dfs(,); anss-=ans-; printf("%d\n",anss);
}
2019.04.02
题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)的更多相关文章
- 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925
题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...
- 洛谷 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]巡逻
题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄.每条道 ...
- 洛谷 P3629 [APIO2010]巡逻
题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...
- luogu题解 P1099 【树网的核】树的直径变式+数据结构维护
题目链接: https://www.luogu.org/problemnew/show/P1099 https://www.lydsy.com/JudgeOnline/problem.php?id=1 ...
- Luogu 3629 [APIO2010]巡逻
先考虑$k = 1$的情况,很明显每一条边都要被走两遍,而连成一个环之后,环上的每一条边都只要走一遍即可,所以我们使这个环的长度尽可能大,那么一棵树中最长的路径就是树的直径. 设直径的长度为$L$,答 ...
- 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)
1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1034 Solved: 562[Submit][St ...
随机推荐
- <tx:advice/> 有关的设置
将描述通过 <tx:advice/> 标签来指定不同的事务性设置.默认的 <tx:advice/> 设置如下: 事务传播设置是 REQUIRED 隔离级别是 DEFAULT 事 ...
- Hadoop HA- zookeeper安装配置
安装集群 1.1 虚拟机: 3台安装好JDK的centos Linux虚拟机 1.2 安装包: 把下载好的zookeeper安装包,官网:http://mirror.bit.edu.cn/apache ...
- 虚拟参考站(VRS)
来源:https://www.sohu.com/a/149415053_391994 一.高精度定位 VRS是虚拟参考站(Virtual Reference Station)的简称.这项技术是CORS ...
- jquery 3D分页翻转滑块
jquery 3D分页翻转滑块,jquery分页,jquery插件,jquery,3D翻转,css3分页,360度旋转,网页特效代码3D分页翻转滑块是一款使用网格样式与滑块效果分页的特效.
- zabbix告警邮件美化
为了更好的用户体验,我们需要尽量美化我们的输出内容,尽量做到整齐划一,让人看了会有很舒服的感觉, 这个好像和苹果的产品一样,给人一种美感让人感觉非常享受. 一般我们的zabbix告警邮件就是纯文字,建 ...
- css 跳转电脑分辨率
因为我们经常在项目中要适配各种屏幕,为了方便前端的开发和测试.我们可以直接把电脑的分辨率调整到需要适配的最小的分辨率,其实还有一种更直接粗暴的方法.直接按F12打开控制台,在收拉浏览器就能看到目前的分 ...
- SQL 优化总结(一)
查询速度慢的原因 查询速度慢原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. ...
- WPF ListView VisualPanel
<ItemsPanelTemplate x:Key="ItemsPanelTemplate1"> &l ...
- 用OpenLayers开发地图应用
项目背景 最近有一个使用全球地图展示数据的项目,用地图展示数据本身没什么难度,但出于安全和保密的考虑,甲方单位要求项目不能连接外网,只能在内网使用,也就是说,我们不得不在内网中部署一个地图服务器,在这 ...
- 3、scala数组
一.Array .Array Buffer 1.Array 在Scala中,Array代表的含义与Java中类似,也是长度不可改变的数组. 此外,由于Scala与Java都是运行在JVM中,双方可以互 ...