@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@

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

最新文章

  1. (准备写)URAL1824 Ifrit Bomber 题解
  2. Jenkins pipeline 入门到精通系列文章
  3. Connection to DB
  4. SQL Server 2012安装时如何不安装自带的Visual Studio
  5. 【转】10分钟搭建NDK的Android开发环境
  6. Azure HDInsight 现已在中国正式发布
  7. Python 写网络爬虫思路分析
  8. java字符串类型常量拼接与变量拼接的区别
  9. java实现文件的断点续传
  10. ECMAScript 6中数组新方法
  11. RabbitMQ简单应用の公平分发(fair dipatch)
  12. 进程池的同步与异步用法Pool
  13. [转帖]linux 内存管理——内核的shmall 和shmmax 参数
  14. sql注入总结(一)--2018自我整理
  15. python使用(五)
  16. 第七章 过滤器基础 Filter
  17. background: inherit制作倒影、单行居中两行居左超过两行省略
  18. Python一个简单的数据库类封装
  19. php安装xdebug后var_dump输出没有格式化的问题
  20. asp.net中GridView传多个值到其它页面的方法

热门文章

  1. Linux下读写UART串口的代码
  2. 关于neo4j的嵌入式和驱动包模式该如何选择,还请解惑
  3. neo4j遍历和图算法
  4. redis jedis存储对象简单操作,map list 自定义对象
  5. day38 03-Spring的IOC和DI的区别
  6. mysql8下载安装及配置
  7. 灵动微本土MCU厂商具有吸引力的增长点
  8. OSGi教程:Resource API Specification
  9. SQLServer —— 流程控制语句
  10. ubuntu16.04如何查看内存和CPU的使用情况