BZOJ4379: [POI2015]Modernizacja autostrady
画个图意会一下,对于每条边,砍掉它后再把这两棵树接起来,新树的最小直径是两棵树最大直径/2(上取整)的和+1,最大值是直径的和
所以对于每条边都求出它分开的两棵树的直径,找到最小最大值后随便搜一下就行了
emmmmmmmmmmmmmmm
dp的过程细节挺爆炸的
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;inline void read(int &x)
{char c; while(!((c=getchar())>='0'&&c<='9'));x=c-'0';while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void up(int &x,const int &y){if(x<y)x=y;}
const int maxn = 1100000;int n;
vector<int>V[maxn];
inline void ins(const int x,const int y){V[x].push_back(y);}int fa[maxn],f[maxn],g[maxn];
void dfs(const int x)
{f[x]=g[x]=0;for(int i=0;i<V[x].size();i++){int y=V[x][i]; if(y==fa[x]) continue;fa[y]=x;dfs(y);up(g[x],max(g[y],f[x]+f[y]+1));up(f[x],f[y]+1);}
}
int u[maxn],ug[maxn];
int pre[maxn],preg[maxn],suf[maxn],sufg[maxn];
int ans1,X1,Y1,ans2,X2,Y2;
void dfs2(const int x)
{for(int i=0;i<V[x].size();i++){int y=V[x][i];pre[i+1]=max(pre[i],y==fa[x]?0:f[y]+1),preg[i+1]=max(preg[i],y==fa[x]?0:max(pre[i]+f[y]+1,g[y]));}suf[V[x].size()]=0; sufg[V[x].size()]=0;for(int i=V[x].size()-1;i>=0;i--){int y=V[x][i];suf[i]=max(suf[i+1],y==fa[x]?0:f[y]+1),sufg[i]=max(sufg[i+1],y==fa[x]?0:max(suf[i+1]+f[y]+1,g[y]));}for(int i=0;i<V[x].size();i++) if(V[x][i]!=fa[x]){int y=V[x][i];int now=max(pre[i]+suf[i+1],u[x]+max(pre[i],suf[i+1])); up(now,ug[x]); up(now,preg[i]); up(now,sufg[i+1]);up(ug[y],now);int temp=(now+1)/2+(g[y]+1)/2+1;up(temp,now); up(temp,g[y]);if(temp<ans1) ans1=temp,Y1=y;temp=now+g[y]+1;if(temp>ans2) ans2=temp,Y2=y;u[y]=max(pre[i],suf[i+1])+1; up(u[y],u[x]+1);}for(int i=0;i<V[x].size();i++) if(V[x][i]!=fa[x]) dfs2(V[x][i]);
}
void trans(const int x)
{f[x]=g[x]=0;for(int i=0;i<V[x].size();i++) if(V[x][i]!=fa[x]){int y=V[x][i]; fa[y]=x; trans(y); up(g[x],g[y]); up(g[x],f[x]+f[y]+1); up(f[x],f[y]+1);}
}
int root,standard;
void search(const int x)
{bool flag=true;if(u[x]>standard) flag=false;for(int i=0;i<V[x].size()&&flag;i++) if(V[x][i]!=fa[x])if(f[V[x][i]]+1>standard) flag=false;if(flag) { root=x; return; }for(int i=0;i<V[x].size();i++)pre[i+1]=max(pre[i],V[x][i]==fa[x]?0:f[V[x][i]]+1);suf[V[x].size()]=0;for(int i=V[x].size()-1;i>=0;i--)suf[i]=max(suf[i+1],V[x][i]==fa[x]?0:f[V[x][i]]+1);for(int i=0;i<V[x].size();i++) if(V[x][i]!=fa[x]){int y=V[x][i];u[y]=max(pre[i],suf[i+1])+1; up(u[y],u[x]+1);}for(int i=0;i<V[x].size()&&root==-1;i++) if(V[x][i]!=fa[x]) search(V[x][i]);
}
void search2(const int x)
{if(u[x]==standard) { root=x; return; }for(int i=0;i<V[x].size();i++)pre[i+1]=max(pre[i],V[x][i]==fa[x]?0:f[V[x][i]]+1);suf[V[x].size()]=0;for(int i=V[x].size()-1;i>=0;i--)suf[i]=max(suf[i+1],V[x][i]==fa[x]?0:f[V[x][i]]+1);for(int i=0;i<V[x].size();i++) if(V[x][i]!=fa[x]){int y=V[x][i];u[y]=max(pre[i],suf[i+1])+1; up(u[y],u[x]+1);}for(int i=0;i<V[x].size()&&root==-1;i++) if(V[x][i]!=fa[x]) search2(V[x][i]);
}
void solve1()
{printf("%d %d %d ",ans1,X1,Y1);fa[X1]=Y1; fa[Y1]=X1;trans(X1); trans(Y1);root=-1; u[X1]=0; standard=(g[X1]+1)/2; search(X1); printf("%d ",root);root=-1; u[Y1]=0; standard=(g[Y1]+1)/2; search(Y1); printf("%d\n",root);
}
void solve2()
{printf("%d %d %d ",ans2,X2,Y2);fa[X2]=Y2; fa[Y2]=X2;trans(X2); trans(Y2);root=-1; u[X2]=0; standard=g[X2]; search2(X2); printf("%d ",root);root=-1; u[Y2]=0; standard=g[Y2]; search2(Y2); printf("%d\n",root);
}int main()
{read(n);for(int i=1;i<n;i++){int x,y; read(x); read(y);ins(x,y); ins(y,x);}fa[1]=0; dfs(1);u[1]=0; ans1=2*n,ans2=-1;dfs2(1); X1=fa[Y1]; X2=fa[Y2];solve1(); solve2();return 0;
}
BZOJ4379: [POI2015]Modernizacja autostrady相关推荐
- BZOJ4379[POI2015] Modernizacja autostrady
BZOJ4379[POI2015] Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的ju距离,请 ...
- [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该序列,寻求区间,它仅出现一次在正确的点区间内值和最大 想了很久,甚至神标题,奔说是水的问题--我醉了 枚举左点 对于每个请求留点右键 ...
最新文章
- 朱俊彦团队提出GAN压缩算法:计算量减少20倍,生成效果不变,GPU、CPU统统能加速...
- Mysql Replication 机制
- 基于Delphi API写的UDP通讯类
- hdu2089 不要62 数位dp
- OpenCV霍夫直线检测的实例(附完整代码)
- Java多线程与并发库高级应用 学习笔记 1-9课
- 轩辕剑之天之痕1-5java_轩辕剑游戏 轩辕剑1到5全系列下载
- 【分布式】分布式架构-ESB SOA
- 学习计划(11.5)
- WMS智能仓储系统成长史?
- Tampermonkey 编写一个首页跳转的脚本
- feign 多个参数放对象_feign架构 原理解析
- python tts库_python 使用百度tts 库合成语音
- android 锁屏界面来电话,android锁屏界面短信解锁指向怎么修改?
- [C++]求模与求余运算
- 分享10款效果惊艳的HTML5图片特效
- 双目立体匹配之代价聚合
- java随机百分比_java随机百分比
- 网站SEO优化工具大全推荐-免费SEO优化工具
- Xilinx FPGA “打一拍”“打两拍”以及IOB含义