@description@

给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输出所有可能的新树的直径的最小值和最大值

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@

设原树为 T,切掉某条边 (a, b) 后分割成树 T1, T2,接上某条边 (c, d) 过后变成新树 T'。

则新树的直径要么不经过 (c, d),即 T1, T2 的直径;要么经过 (c, d)。

我们枚举边 (a, b),则我们能够控制的只有经过 (c, d) 的路径。

实际上就是从 c 出发的最远距离 + 从 d 出发的最远距离 + 1。

如果要求解最大直径,则要经过 (c, d) 的路径尽量大,显然把 T1, T2 的直径连起来就是了。

如果要求解最小直径,则要经过 (c, d) 的路径尽量小,方法是把 T1, T2 的直径的中点连起来。

证明可以用一个点出发的最远距离的终点一定是直径的端点这样一个结论。

dfs 的时候,维护出父亲那一部分的联通块的直径长度与该结点为根的子树中的直径长度即可。

子树直径是一个经典的树形 dp。

父亲那一部分,考虑从父亲的父亲到父亲增加的几种路径:父亲为根的这棵子树内不经过父亲的路径,经过父亲的路径,由父亲为根的这棵子树向上经过父亲的父亲的路径。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 500000 + 5;
const int INF = int(1E9);
struct edge{
int to; edge *nxt;
}edges[2*MAXN], *adj[MAXN], *ecnt=&edges[0];
void addedge(int u, int v) {
edge *p = (++ecnt);
p->to = v, p->nxt = adj[u], adj[u] = p;
p = (++ecnt);
p->to = u, p->nxt = adj[v], adj[v] = p;
}
int fa[MAXN], mxl[MAXN], dp[MAXN];
void dfs1(int x) {
int sec = 0; dp[x] = mxl[x] = 0;
for(edge *p=adj[x];p;p=p->nxt) {
if( p->to == fa[x] ) continue;
fa[p->to] = x; dfs1(p->to);
dp[x] = max(dp[x], dp[p->to]);
if( mxl[p->to] > mxl[x] ) {
sec = mxl[x];
mxl[x] = mxl[p->to];
}
else if( mxl[p->to] > sec )
sec = mxl[p->to];
}
dp[x] = max(dp[x], sec + mxl[x]);
mxl[x]++;
}
int mn, mx, m1, m2;
void dfs2(int x, int nw, int k) {
if( x != 1 ) {
if( nw + dp[x] + 1 > mx ) {
mx = nw + dp[x] + 1;
m2 = x;
}
if( max(max(dp[x], nw), (dp[x] + 1)/2 + (nw + 1)/2 + 1) < mn ) {
mn = max(max(dp[x], nw), (dp[x] + 1)/2 + (nw + 1)/2 + 1);
m1 = x;
}
}
int a = 0, b = 0, c = 0, d = 0, e = 0;
for(edge *p=adj[x];p;p=p->nxt) {
if( p->to == fa[x] ) continue;
if( mxl[p->to] >= mxl[a] ) {
c = b;
b = a;
a = p->to;
}
else if( mxl[p->to] >= mxl[b] ) {
c = b;
b = p->to;
}
else if( mxl[p->to] >= mxl[c] ) {
c = p->to;
}
if( dp[p->to] >= dp[d] ) {
e = d;
d = p->to;
}
else if( dp[p->to] >= dp[e] ) {
e = p->to;
}
}
for(edge *p=adj[x];p;p=p->nxt) {
if( p->to == fa[x] || p->to == a || p->to == b ) continue;
dfs2(p->to, max(max(mxl[a] + mxl[b], dp[p->to == d ? e : d]), max(nw, mxl[a] + k)), max(k, mxl[a]) + 1);
}
if( a ) dfs2(a, max(max(mxl[b] + mxl[c], dp[a == d ? e : d]), max(nw, mxl[b] + k)), max(k, mxl[b]) + 1);
if( b ) dfs2(b, max(max(mxl[a] + mxl[c], dp[b == d ? e : d]), max(nw, mxl[a] + k)), max(k, mxl[a]) + 1);
}
int que[MAXN], dis[MAXN], n;
int bfs(int s, int x) {
for(int i=1;i<=n;i++)
dis[i] = INF;
int hd = 1, tl = 0, mx = s;
que[++tl] = s; dis[s] = 0;
while( hd <= tl ) {
int f = que[hd++];
if( dis[f] > dis[mx] ) mx = f;
for(edge *p=adj[f];p;p=p->nxt) {
if( p->to == x ) continue;
if( dis[f] + 1 < dis[p->to] ) {
que[++tl] = p->to;
dis[p->to] = dis[f] + 1;
}
}
}
return mx;
}
int arr[MAXN];
void dfs3(int x, int y, int d, int fa) {
arr[d] = x;
if( x == y ) printf(" %d", arr[d/2]);
for(edge *p=adj[x];p;p=p->nxt) {
if( p->to == fa ) continue;
dfs3(p->to, y, d + 1, x);
}
}
int main() {
scanf("%d", &n);
for(int i=1;i<n;i++) {
int u, v; scanf("%d%d", &u, &v);
addedge(u, v);
}
mn = n, mx = 0;
dfs1(1), dfs2(1, 0, 0);
printf("%d %d %d", mn, m1, fa[m1]);
dfs3(bfs(fa[m1], m1), bfs(bfs(fa[m1], m1), m1), 0, 0);
dfs3(bfs(m1, fa[m1]), bfs(bfs(m1, fa[m1]), fa[m1]), 0, 0);
puts("");
printf("%d %d %d", mx, m2, fa[m2]);
printf(" %d", bfs(fa[m2], m2));
printf(" %d", bfs(m2, fa[m2]));
puts("");
}

@details@

这么水的题为什么会这么少人做啊。。。

@bzoj - 4379@ [POI2015] Modernizacja autostrady的更多相关文章

  1. 【BZOJ4379】[POI2015]Modernizacja autostrady 树形DP

    [BZOJ4379][POI2015]Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输 ...

  2. BZOJ4379 : [POI2015]Modernizacja autostrady

    两遍树形DP求出每个点开始往上往下走的前3长路以及每个点上下部分的直径. 枚举每条边断开,设两边直径分别为$A,B$,则: 对于第一问,连接两边直径的中点可得直径为$\max(A,B,\lfloor\ ...

  3. [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]

    题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...

  4. bzoj 4386: [POI2015]Wycieczki

    bzoj 4386: [POI2015]Wycieczki 这题什么素质,爆long long就算了,连int128都爆……最后还是用long double卡过的……而且可能是我本身自带大常数吧,T了 ...

  5. BZOJ 4385: [POI2015]Wilcze doły

    4385: [POI2015]Wilcze doły Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 648  Solved: 263[Submit][ ...

  6. BZOJ 4384: [POI2015]Trzy wieże

    4384: [POI2015]Trzy wieże Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 217  Solved: 61[Submit][St ...

  7. Bzoj 3747: [POI2015]Kinoman 线段树

    3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 553  Solved: 222[Submit][Stat ...

  8. BZOJ 3747 POI2015 Kinoman 段树

    标题效果:有m点,每个点都有一个权值.现在我们有这个m为点的长度n该序列,寻求区间,它仅出现一次在正确的点区间内值和最大 想了很久,甚至神标题,奔说是水的问题--我醉了 枚举左点 对于每个请求留点右键 ...

  9. BZOJ 4380 [POI2015]Myjnie | DP

    链接 BZOJ 4380 题面 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个 ...

随机推荐

  1. 提升mysql服务器性能(HA MMM MHA MaxScale)

    原文:提升mysql服务器性能(HA MMM MHA MaxScale) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/detai ...

  2. day37 07-Hibernate二级缓存:查询缓存

    查询缓存是比二级缓存功能更强大的缓存.必须把二级缓存配置好之后才能用查询缓存,否则是用不了的.二级缓存主要是对类的缓存/对象缓存.查询缓存针对对象也是可以的(因为功能比二级缓存更强大),而且还可以针对 ...

  3. Laravel 5.2 使用 JWT 完成多用户认证 | Laravel China 社区 - 高品质的 Laravel 开发者社区 - Powered by PHPHub

    Json Web Token# JWT代表Json Web Token.JWT能有效地进行身份验证并连接前后端. 降地耦合性,取代session,进一步实现前后端分离 减少服务器的压力 可以很简单的实 ...

  4. 安装tengine及淘宝会话保持模块

    安装tengine及淘宝会话保持模块 下载http://tengine.taobao.org/ 解压tar -zxvf tengine-2.3.0.tar.gz 安装GCC: yum -y insta ...

  5. Spring_代理

    1.代理模式. 2.静态代理原理及实践. 3.动态代理原理及实践. 4.Spring AOP原理及实战. 静态代理原理及实践 package test.staticProxy; // 接口 publi ...

  6. 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树

    题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...

  7. Linux操作系统各版本ISO镜像下载(包括oracle linux\redhat\centos\u

    Linux操作系统各版本ISO镜像下载(包括oracle linux\redhat\centos\ubuntu\debian等) 1.Oracle Linux(下载地址) (1)OracleLinux ...

  8. phpExcel 操作示例

    片段 1 片段 2 phpExcel 操作示例 <?php //写excel //Include class require_once('Classes/PHPExcel.php'); requ ...

  9. IDEA 运行maven项目配置

  10. typroa 和markdown基操

    目录 标题 一级标题 二级标题 字体 图片 来插入图片,如在同意文件夹上,可直接加图片名 数学公式 编辑表格 标题 一级标题 二级标题 三级标题 无序标题 *加空格,无序标题 也可以使用ctrl = ...