BZOJ4379[POI2015] Modernizacja autostrady
BZOJ4379[POI2015] Modernizacja autostrady
Description
给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的ju距离,请输出所有可能的新树的直径的最小值和最大值。
Input
第一行包含一个正整数n(3<=n<=500000),表示这棵树的点数。
接下来n-1行,每行包含两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。Output
第一行输出五个正整数k,x1,y1,x2,y2,其中k表示新树直径的最小值,x1,y1表示这种情况下要去掉的边的两端点,x2,y2表示这种情况下要加上的边的两端点。
第二行输出五个正整数k,x1,y1,x2,y2,其中k表示新树直径的最大值,x1,y1表示这种情况下要去掉的边的两端点,x2,y2表示这种情况下要加上的边的两端点。
若有多组最优解,输出任意一组。
Sample Input
6
1 2
2 3
2 4
4 5
6 5
Sample Output
3 4 2 2 5
5 2 1 1 6
Solution:
网上的题解好像都是直接无脑dp的,好像只有我是推了性质去做的…
这个性质还是比较好推的吧。
先考虑最大值:
首先我们把直径拎出来,然后分断边在直径上和非直径上。
在直径上:
直接在直径上dp,一个直径点左边子树中直径的长度就是该点的外挂树的深度加上这点到直径左端点的距离或者是从左边一个点转移过来。右边同理。直接在直径上枚举这条断边,答案就是D1+D2+1D1+D2+1。(D1D2D1D2即是左边子树的直径和右边子树的直径)
不在直径上:
首先直径这一部分子树的直径肯定就直接是直径了,然后我们要使得剩下的子树直径最大,所以就直接断在与直径点相连的这一条边上,因为小的子树的直径肯定不会大于大的子树。于是直接每个点暴力dfs过去算一下就好了,复杂度O(n)O(n)。
再考虑最小值:
一样地分断边在直径上和断边不在直径上考虑。
在直径上:
一样的dp,答案就是max(D1,D2,D12+D22+1)max(D1,D2,\frac{D1}2+\frac{D2}2+1),最后断点再dfs一下就可以求出来了。
不在直径上:
那么最后的直径最少也是原直径了,还不如不做操作(删边与添边相同)。
于是就能够解决这道题了,复杂度O(n)O(n)。代码写的有点难看。
#include<stdio.h>
#include<string.h>
#include<iostream>
#define M 500005
using namespace std;
struct Edge{int to,nxt;}Edge[M<<1];
int tot=0,Head[M],n;
void Addedge(int a,int b){Edge[++tot].to=b;Edge[tot].nxt=Head[a];Head[a]=tot;Edge[++tot].to=a;Edge[tot].nxt=Head[b];Head[b]=tot;
}
bool mark[M];
int mx,id,d[M],Q[M],sz,dp1[M],dp2[M];
void dfs1(int x,int fa,int dis){if(dis>mx)mx=dis,id=x;d[x]=dis;for(int i=Head[x];~i;i=Edge[i].nxt){int to=Edge[i].to;if(to==fa||mark[to])continue;dfs1(to,x,dis+1);}
}
void dfs2(int x,int dis){Q[++sz]=x;for(int i=Head[x];~i;i=Edge[i].nxt){int to=Edge[i].to;if(d[to]!=dis-1)continue;dfs2(to,dis-1);break;}
}
void solve(){mx=-1;dfs1(1,0,0);mx=-1;dfs1(id,0,0);int D=mx;sz=0;for(int i=1;i<=n;i++)if(d[i]==D){id=i;break;}dfs2(id,D);for(int i=1;i<=sz;i++){mark[Q[i-1]]=mark[Q[i+1]]=true;mx=-1;dfs1(Q[i],0,0);mark[Q[i-1]]=mark[Q[i+1]]=false;if(i+mx-1>dp1[i-1])dp1[i]=i+mx-1;else dp1[i]=dp1[i-1];}for(int i=sz;i>=1;i--){mark[Q[i-1]]=mark[Q[i+1]]=true;mx=-1;dfs1(Q[i],0,0);mark[Q[i-1]]=mark[Q[i+1]]=false;if(sz-i+mx>dp2[i+1])dp2[i]=sz-i+mx;else dp2[i]=dp2[i+1];}int id11,id12,id13,id14,id21,id22,id23,id24;int ans1=0,ans2=n+1;for(int i=1;i<sz;i++)if(dp1[i]+dp2[i+1]+1>ans1)ans1=dp1[i]+dp2[i+1]+1,id11=Q[i],id12=Q[i+1],id13=Q[1],id14=Q[sz];for(int i=1;i<=sz;i++){for(int j=Head[Q[i]];~j;j=Edge[j].nxt){int to=Edge[j].to;if(to==Q[i+1]||to==Q[i-1])continue;mark[Q[i]]=true;mx=-1;dfs1(to,Q[i],0);mx=-1;dfs1(id,0,0);mark[Q[i]]=false;if(D+mx+1>ans1)ans1=D+mx+1,id11=Q[i],id12=to,id13=id,id14=Q[1];}}for(int i=1;i<sz;i++){int t=(dp1[i]+1)/2+(dp2[i+1]+1)/2+1;t=max(t,dp1[i]);t=max(t,dp2[i+1]);if(t<ans2)ans2=t,id21=Q[i],id22=Q[i+1];}mark[id22]=true;mx=-1;dfs1(id21,id22,0);mx=-1;dfs1(id,0,0);sz=0;dfs2(id,mx);id23=Q[(sz+1)>>1];mark[id22]=false;mark[id21]=true;mx=-1;dfs1(id22,id21,0);mx=-1;dfs1(id,0,0);sz=0;dfs2(id,mx);id24=Q[(sz+1)>>1];mark[id21]=false;printf("%d %d %d %d %d\n",ans2,id21,id22,id23,id24);printf("%d %d %d %d %d\n",ans1,id11,id12,id13,id14);
}
int main(){memset(Head,-1,sizeof(Head));scanf("%d",&n);for(int i=1;i<n;i++){int a,b;scanf("%d %d",&a,&b);Addedge(a,b);}solve();return 0;
}
BZOJ4379[POI2015] Modernizacja autostrady相关推荐
- BZOJ4379: [POI2015]Modernizacja autostrady
画个图意会一下,对于每条边,砍掉它后再把这两棵树接起来,新树的最小直径是两棵树最大直径/2(上取整)的和+1,最大值是直径的和 所以对于每条边都求出它分开的两棵树的直径,找到最小最大值后随便搜一下就行 ...
- [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...
- BZOJ4379 : [POI2015]Modernizacja autostrady
两遍树形DP求出每个点开始往上往下走的前3长路以及每个点上下部分的直径. 枚举每条边断开,设两边直径分别为$A,B$,则: 对于第一问,连接两边直径的中点可得直径为$\max(A,B,\lfloor\ ...
- 【BZOJ4379】[POI2015]Modernizacja autostrady 树形DP
[BZOJ4379][POI2015]Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输 ...
- 【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)
3747: [POI2015]Kinoman Time Limit: 60 Sec Memory Limit: 128 MB Submit: 830 Solved: 338 Description ...
- [POI2015]CZA
[POI2015]CZA p很小,讨论 p=0... p=1... p=2:n-1放左或者放右两种情况,剩下怎么放是固定的,模拟然后判断即可 p=3: 正着做要状压,类似放书和排座位那些题,考虑以某个 ...
- P3591 [POI2015]ODW(分块)
P3591 [POI2015]ODW 给定一颗有nnn个节点的树,点有点权,给定一个长度为nnn的排列ppp,给定一个长度为n−1n - 1n−1的数组ccc, 我们会在树上进行n−1n - 1n−1 ...
- bzoj4380[POI2015]Myjnie dp
[POI2015]Myjnie Time Limit: 40 Sec Memory Limit: 256 MBSec Special Judge Submit: 368 Solved: 185 ...
- BZOJ 3747 POI2015 Kinoman 段树
标题效果:有m点,每个点都有一个权值.现在我们有这个m为点的长度n该序列,寻求区间,它仅出现一次在正确的点区间内值和最大 想了很久,甚至神标题,奔说是水的问题--我醉了 枚举左点 对于每个请求留点右键 ...
最新文章
- 语义分割--Large Kernel Matters--Improve Semantic Segmentation by Global Convolutional Network
- Linux学习之Vi编辑器常用命令
- DNS RR字段含义
- fedora apache php,Fedora 20下安装搭建LAMP环境Apache+MySQL+PHP
- 【图解】一图了解《上海市推进新一代信息基础设施建设 助力提升城市能级和核心竞争力三年行动计划(2018-2020年)》...
- php pdf 加密 签名 时间戳,在现有PDF签名上添加签名时间戳
- SAP Spartacus的自定义路由
- 四十三 常用内建模块 base64
- oracle存储sql片段引入_强大的跨数据库访问组件 UniDAC使用教程:注释和SQL函数...
- 微软想证明Windows比Chrome好 主要源自恐惧?
- 关于 IO 和 NIO 的思考
- 浅析那些带着“主角光环“的泰坦尼克号幸存者(下)
- PHP中获取html页面传值
- ios 高德挪动地图获取经纬度_iOS 高德地图 根据经纬度解析成位置
- 八爪鱼怎样导入mysql_八爪鱼采集数据导出sqlserver数据库(手动、自动两种方式) - 八爪鱼采集器...
- Java8 新特性并发篇(一) | 线程与执行器
- 共享经济突围路在何方 ?共享洗衣机能否突围?
- 解决ps不能直接把文件拖进去的问题
- java创建word并设置基本属性,Java 生成word如何将word设置为只读属性
- 三位数自动递增编号函数_Excel单元格自动填充编号、序列、18位长数字与数字+字母+数字...
热门文章
- 分享即时通讯开发之实时音视频技术基础知识
- 天黑请闭眼--杀吧专用(C#版 附源码)
- 凭证录入模板-检查核算项目研发项目是否录入
- 台式计算机小键盘,台式电脑软键盘在哪里,初学电脑
- phpmail通过qq发邮箱失败_PHP中利用PHPMailer配合QQ邮箱实现发邮件
- mysql 家谱树查询_中国家谱族谱数据库可以登录、查询了
- 被动信息收集:使用OSINT框架进行信息收集
- 史上最全的定位攻略,您应该知道的定位方法。
- 写出HTML的基本结构 做简要说明,北京市顺义区2017年--2018年届高三二模语文试题(卷)与答案解析.doc...
- 计算机特殊的标点符号教案,三年级下册信息技术《标点符号的输入》教学设计...