@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. hystrix熔断器

    在一个具有多服务的应用中,假如由于其中某一个服务出现问题,导致响应速度变慢,或是根本没有响应返回,会导致它的服务消费者由于长时间的等待,消耗尽线程,进而影响到对其他服务的线程调用,进而会转变为整个应用 ...

  2. MySQL忘记root密码重置密码(5.7版本)

    网上找了一堆方法都不行,经过折腾一番,发现MySQL不同版本重置密码也存在一定的差异!记录下Mysql5.7.18版本的重置密码方法. 1.找到/etc/mysql/my.cnf 修改此文件添加一行s ...

  3. 洛谷P1029 最大公约数和最小公倍数问题 [2017年6月计划 数论02]

    P1029 最大公约数和最小公倍数问题 题目描述 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件: 1 ...

  4. Linux下安装ssdb

    安装ssdb wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip unzip master cd ...

  5. php中 重载的方法

    php中 重载(一)这个文章,谢谢.作为初学者,大牛勿喷: 基本是两个方法 __call,当调用对一个不可访问的对象方法时,会自动执行该魔术方法!(对象调用) 典型的两种处理方式: 1,给出友好的提示 ...

  6. java如何访问memcache

    1       Memcache是什么 Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的 ...

  7. 开源PaaS平台:Cloudify

    Cloudify是gigaspaces公司推出的基于java的paas平台. refer to :http://timeson.iteye.com/blog/1699730

  8. Neo4j文档

    Neo4j 图数据库 主要有节点和关系,关系是有向边,节点和关系都有属性,属性是键值对 Neo4j使用CQL语句,代表Cypher查询语言 相当于SQL 统一声明 在所有的语句中均有结构 <no ...

  9. 总体<导学>

    有一些奇奇怪怪的数据集 波士顿房价数据集 使用sklearn.datasers.load_boston 加载相关的数据集 重要参数 return_X_y 表示是否返回target (价格) 默认为Fa ...

  10. JSP Web第三章整理复习 开发环境搭建

    P86  WEB工作原理 用户使用浏览器通过HTTP协议请求服务器上的Web资源,服务器接收到该请求后,读取请求的URI所标识的资源,加上其他资源发送给客户端的浏览器,浏览器解析响应中的HTML数据, ...