@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. 学习JDK1.8集合源码之--ArrayDeque

    1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...

  2. python基础--魔法方法、迭代器、上下文管理

    isinstance:判断一个对象是否是某个类的实例 参数一:要判断的对象 参数二:要判断的类型 issubclass:判断一个类是否是另一个类的子类 参数一:是待判断的子类 参数二:待判断的父类 _ ...

  3. 【模板】KMP [2017年5月计划 清北学堂51精英班Day2]

    Day2就搞一个KMP把  马拉车.AC自动机等准备省选的时候再说.. 模板题: 1204 寻找子串位置 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 青铜 Bronze     ...

  4. vue自定义指令之拖动页面的元素

    此案例中,用到了鼠标事件onmousedown.onmousemove.onmouseup 源代码如下: <!doctype html><html lang="en&quo ...

  5. 简单的layui二级联动

    用layui实现省市二级联动, 需要注意的是使用layui之后, 你看到的下拉选框就不是option了,而是一些div 1.select表单 2.JS, ajax返回的是普通的数组

  6. sqlyog备份数据和导入备份数据

    使用sqlyog备份数据 Database -> Backup/Export  -> Backup Database As SQL Dump 根据自己实际情况,看需要 导出表结构或者仅仅只 ...

  7. NoSQL最新现状和趋势:云NoSQL数据库将成重要增长引擎

    NoSQL最早起源于1998年,但从2009年开始,NoSQL真正开始逐渐兴起和发展.回望历史应该说NoSQL数据库的兴起,完全是十年来伴随互联网技术,大数据数据的兴起和发展,NoSQL在面临大数据场 ...

  8. stack的基本使用方式

    #include <iostream> #include <stack>//头文件 using namespace std; stack<int> S; int m ...

  9. 运行Jmeter时,响应数据中文乱码问题解决办法

    需要修改jmeter中的配置,在Jmeter安装目录/bin/jmeter.properties文件中进行修改: sampleresult.default.encoding默认为ISO-8859-1, ...

  10. 并发模式与 RPS 模式之争,性能压测领域的星球大战

    本文是<如何做好性能压测>系列专题分享的第四期,该专题将从性能压测的设计.实现.执行.监控.问题定位和分析.应用场景等多个纬度对性能压测的全过程进行拆解,以帮助大家构建完整的性能压测的理论 ...