[BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意
给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值。
\(n\leq 5\times 10^5\) .
分析
记断掉一条边之后两棵树的直径为 \(A,B\) ,最长直径为 \(A+B+1\) 最短为 \(\max\{A\ ,B\ ,\lceil \frac{A}{2}\rceil+\lceil \frac{B}{2} \rceil +1\}\) .
维护每个点不同子树的前3长链和向上的最长链、不同子树的前2长路径和向上子树的最长路径。
这样枚举断掉一条边之后换根 \(dp\) 一下就可以求得父节点所在树的直径了。
方案可以按照 \(dfs\) 找树的直径的方式构造答案。
总时间复杂度为 \(O(n)\) 。
换根dp可以解决树断一条边以及不同根询问等问题。
代码
#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define re(x) memset(x,0,sizeof x)
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=5e5 + 7,inf=0x3f3f3f3f;
int n,edc=1,edg1,edg2,ans1=inf,ans2,ban[N<<1];
int f1[N][3],f2[N],g1[N][2],g2[N],fu[N],f[N][4],g[N][3],head[N];
struct edge{
int last,to;
edge(){}edge(int last,int to):last(last),to(to){}
}e[N*2];
void Add(int a,int b){
e[++edc]=edge(head[a],b),head[a]=edc;
e[++edc]=edge(head[b],a),head[b]=edc;
}
bool cmp(int x,int y){return x>y;}
void dfs1(int u,int fa){
go(u)if(v^fa){
dfs1(v,u);
int x=fu[v];
if(x>g1[u][0]) g1[u][1]=g1[u][0],g1[u][0]=x;
else if(x>g1[u][1]) g1[u][1]=x;
x=f1[v][0]+1;
if(x>f1[u][0]) f1[u][2]=f1[u][1],f1[u][1]=f1[u][0],f1[u][0]=x;
else if(x>f1[u][1]) f1[u][2]=f1[u][1],f1[u][1]=x;
else if(x>f1[u][2]) f1[u][2]=x;
}
fu[u]=max(g1[u][0],f1[u][0]+f1[u][1]);
}
void dfs2(int u,int fa){
for(int i=0;i<3;++i) f[u][i]=f1[u][i];f[u][3]=f2[u];sort(f[u],f[u]+4,cmp);
for(int i=0;i<2;++i) g[u][i]=g1[u][i];g[u][2]=g2[u];sort(g[u],g[u]+3,cmp);
go(u)if(v^fa){
int x=0,cnt=0;
for(int j=0,fg=0;j<4;++j){
if(f[u][j]==f1[v][0]+1&&!fg){fg=1;continue;}
x=f[u][j]; break;
}
f2[v]=x+1,x=0;
for(int j=0,fg=0;j<4;++j){
if(f[u][j]==f1[v][0]+1&&!fg) {fg=1;continue;}
x+=f[u][j];if(++cnt==2) break;
}
for(int j=0,fg=0;j<3;++j){
if(g[u][j]==fu[v]&&!fg) {fg=1;continue;}
Max(x,g[u][j]);break;
}
g2[v]=x;
int tmp=max(max(x,fu[v]),(x+1)/2+(fu[v]+1)/2+1);
if(ans1>tmp) ans1=tmp,edg1=i;
tmp=(x+fu[v]+1);
if(ans2<tmp) ans2=tmp,edg2=i;
dfs2(v,u);
}
}
int fa[N],mx,cho,tp,tmp[N];
void dfs(int u,int dis){
if(dis>=mx) mx=dis,cho=u;
go(u)if(v^fa[u]&&!ban[i]) fa[v]=u,dfs(v,dis+1);
}
int main(){
n=gi();
rep(i,1,n-1) Add(gi(),gi());
dfs1(1,0); dfs2(1,0);
printf("%d %d %d",ans1,e[edg1].to,e[edg1^1].to);
ban[edg1]=ban[edg1^1]=1;
int x=e[edg1].to;dfs(x,0);
re(fa),x=cho,mx=0,dfs(x,0);tp=0;for(int i=cho;i;i=fa[i]) tmp[++tp]=i;printf(" %d",tmp[tp+1>>1]);
re(fa),x=e[edg1^1].to,mx=0,dfs(x,0);
re(fa),x=cho,mx=0,dfs(x,0);tp=0;for(int i=cho;i;i=fa[i]) tmp[++tp]=i;printf(" %d\n",tmp[tp+1>>1]);
printf("%d %d %d",ans2,e[edg2].to,e[edg2^1].to);
ban[edg1]=ban[edg1^1]=0,ban[edg2]=ban[edg2^1]=1;
re(fa),x=e[edg2].to,mx=0,dfs(x,0);printf(" %d",cho);
re(fa),x=e[edg2^1].to,mx=0,dfs(x,0);printf(" %d\n",cho);
return 0;
}
[BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]的更多相关文章
- BZOJ4379 : [POI2015]Modernizacja autostrady
两遍树形DP求出每个点开始往上往下走的前3长路以及每个点上下部分的直径. 枚举每条边断开,设两边直径分别为$A,B$,则: 对于第一问,连接两边直径的中点可得直径为$\max(A,B,\lfloor\ ...
- 【BZOJ4379】[POI2015]Modernizacja autostrady 树形DP
[BZOJ4379][POI2015]Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输 ...
- 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市
P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...
- 模拟赛:树和森林(lct.cpp) (树形DP,换根DP好题)
题面 题解 先解决第一个子问题吧,它才是难点 Subtask_1 我们可以先用一个简单的树形DP处理出每棵树内部的dis和,记为dp0[i], 然后再用一个换根的树形DP处理出每棵树内点 i 到树内每 ...
- Acesrc and Travel(2019年杭电多校第八场06+HDU6662+换根dp)
题目链接 传送门 题意 两个绝顶聪明的人在树上玩博弈,规则是轮流选择下一个要到达的点,每达到一个点时,先手和后手分别获得\(a_i,b_i\)(到达这个点时两个人都会获得)的权值,已经经过的点无法再次 ...
- 2018.10.15 NOIP训练 水流成河(换根dp)
传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...
- 小奇的仓库:换根dp
一道很好的换根dp题.考场上现场yy十分愉快 给定树,求每个点的到其它所有点的距离异或上m之后的值,n=100000,m<=16 只能线性复杂度求解,m又小得奇怪.或者带一个log像kx一样打一 ...
- 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)
题意 题目链接:https://www.luogu.org/problem/P4827 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...
- bzoj 3566: [SHOI2014]概率充电器 数学期望+换根dp
题意:给定一颗树,树上每个点通电概率为 $q[i]$%,每条边通电的概率为 $p[i]$%,求期望充入电的点的个数. 期望在任何时候都具有线性性,所以可以分别求每个点通电的概率(这种情况下期望=概率 ...
随机推荐
- WebAPI返回时间数据不带T
最近一段时间项目里面使用WebAPI比较多,但是在返回时间数据的时候回默认带上T,就像这样子 "2016-04-21T13:26:17.4701811+08:00", 这样的数据在 ...
- Python 面向对象补充
什么是面向对象编程 类 + 对象 class 类: def 函数1(): pass def 函数2(): pass obj是对象, 实例化的过程 obj = 类() obj.函数1() 例1 , 某些 ...
- kudu基础入门
1.kudu介绍 1.1 背景介绍 在KUDU之前,大数据主要以两种方式存储: (1)静态数据: 以 HDFS 引擎作为存储引擎,适用于高吞吐量的离线大数据分析场景.这类存储的局限性是数据无法进行随机 ...
- openlayers5实战--踩坑总结
1.接口返回圆心坐标和半径,直接通过new Circle(center,radius)添加圆形feature变小问题. 解决办法: new Feature()的geometry参数不能直接赋值new ...
- swift语言的特征:类型系统与函数式编程:swift是面向类型和面向函数编程的语言
swift语言的特征: 类型系统:值类型与引用类型.泛型.协议类型 函数式编程:
- BZOJ2460:[BJWC2011]元素(贪心,线性基)
Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石. 一般地,矿石越多则法力越 ...
- [BeiJing2006]狼抓兔子
题面 一眼看就是最小割板子题,建图也很直观,注意每一条边建双向边其实不用建4条边,只要反向边的容量和正边相同就行.然后直接跑最大流板子就行.不过此题拿vector存图会MLE……而拿链前存图就能卡过去 ...
- Spark项目之电商用户行为分析大数据平台之(一)项目介绍
一.项目概述 本项目主要用于互联网电商企业中,使用Spark技术开发的大数据统计分析平台,对电商网站的各种用户行为(访问行为.购物行为.广告点击行为等)进行复杂的分析.用统计分析出来的数据,辅助公司中 ...
- mysql用户创建与授权
一. 创建用户 命令: CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明: username:你将创建的用户名 host:指定该用户 ...
- 开启路由转发 - route add -net 0.0.0.0 netmask 0.0.0.0 gateway 192.168.0.131 window tracert 追踪路由
1.登录方式内网访问172.28.101.0/19网段的方法:在192.168.1.0/24网段的上网机器上,或在自己的操作机上加个192.168.1.0网段的ip,注意不要跟别人设置的冲突了,并添加 ...