@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. 洛谷 P1217 [USACO1.5]回文质数 Prime Palindromes【取回文数/数论/字符串】

    题目描述 因为151既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 是回文质数. 写一个程序来找出范围[a,b](5 <= a < b <= 100,000 ...

  2. python实例 函数

    #! /usr/bin/python # -*- coding: utf8 -*- def sum(a,b):     return a+b func = sum r = func(5,6) prin ...

  3. SQL SERVER 自增列的方法

    declare @Table_name varchar(60) set @Table_name = ''; if Exists(Select top 1 1 from sysobjects       ...

  4. web前端学习(二)html学习笔记部分(11)-- 没有标号记录的知识合集

    这一部分内容相对比较简单,就不按规矩排序了.(主要是网站上也没有这一部分内容的排序) 1.  html5的 非主体结构元素 学习笔记(1)里面记录过. 2.  html5表单提交和PHP环境搭建 1. ...

  5. laravel-admin 安装(总结)

    https://www.jianshu.com/p/844b05e4c45a laravel-admin 是一个可以快速帮你构建后台管理的工具,它提供的页面组件和表单元素等功能,能帮助你使用很少的代码 ...

  6. Centos7.2源码编译安装LA(N)MP

    LAMP环境中php是作为apache的模块安装的,所以安装顺序是php放在apache的后面安装,这样便于安装php时可以在apache的模块目录生成对应的php模块. apache版本:2.4.3 ...

  7. Linux SSH远程链接 短时间内断开

    Linux SSH远程链接 短时间内断开 操作系统:RedHat 7.5 问题描述: 在进行SSH链接后,时不时的就断开了 解决方案: 修改 /etc/ssh/sshd_config 文件,找到 Cl ...

  8. php_imagick是怎么实现复古效果的呢?

    php_imagick程序示例 1.创建一个缩略图并显示出来 <?phpheader('Content-type: image/jpeg');$image = new Imagick('imag ...

  9. Python 基于 NLP 的文本分类

    这是前一段时间在做的事情,有些python库需要python3.5以上,所以mac请先升级 brew安装以下就好,然后Preference(comm+',')->Project: Text-Cl ...

  10. spring-cloud-zuul跨域问题解决

    问题发现 正常情况下,跨域是这样的: 1. 微服务配置跨域+zuul不配置=有跨域问题 2. 微服务配置+zuul配置=有跨域问题 3. 微服务不配置+zuul不配置=有跨域问题 4. 微服务不配置+ ...