codeforces1528c_us open of surfing

codeforces1528c_us open of surfingCodeForces 1073F Choosing Two Paths

大家好,又见面了,我是你们的朋友全栈君。

Description

You are given an undirected unweighted tree consisting of \(n\) vertices.

An undirected tree is a connected undirected graph with \(n−1\) edges.

Your task is to choose two pairs of vertices of this tree (all the chosen vertices should be distinct) \((x_1,y_1)\) and \((x_2,y_2)\) in such a way that neither \(x_1\) nor \(y_1\) belong to the simple path from \(x_2\) to \(y_2\) and vice versa (neither \(x_2\) nor \(y_2\) should not belong to the simple path from \(x_1\) to \(y_1\)).

It is guaranteed that it is possible to choose such pairs for the given tree.

Among all possible ways to choose such pairs you have to choose one with the maximum number of common vertices between paths from \(x_1\) to \(y_1\) and from \(x_2\) to \(y_2\). And among all such pairs you have to choose one with the maximum total length of these two paths.

It is guaranteed that the answer with at least two common vertices exists for the given tree.

The length of the path is the number of edges in it.

The simple path is the path that visits each vertex at most once.

Input

The first line contains an integer \(n\) — the number of vertices in the tree \((6 \le n \le 2 \cdot 10^5)\).

Each of the next \(n−1\) lines describes the edges of the tree.

Edge \(i\) is denoted by two integers \(u_i\) and \(v_i\), the labels of vertices it connects \((1\le u_i,v_i\le n, u_i \neq v_i)\).

It is guaranteed that the given edges form a tree.

It is guaranteed that the answer with at least two common vertices exists for the given tree.

Output

Print any two pairs of vertices satisfying the conditions described in the problem statement.

It is guaranteed that it is possible to choose such pairs for the given tree.

Examples

Input

7
1 4
1 5
1 6
2 3
2 4
4 7

Output

3 6
7 5

Input

9
9 3
3 5
1 2
4 3
4 7
1 7
4 6
3 8

Output

2 9
6 8

Input

10
6 8
10 3
3 7
5 8
1 7
7 2
2 9
2 8
1 4

Output

10 6
4 5

Input

11
1 2
2 3
3 4
1 5
1 6
6 7
5 8
5 9
4 10
4 11

Output

9 11
8 10

Note

The picture corresponding to the first example:

img

The intersection of two paths is \(2\) (vertices \(1\) and \(4\)) and the total length is \(4+3=7\).

The picture corresponding to the second example:

img

The intersection of two paths is \(2\) (vertices \(3\) and \(4\)) and the total length is \(5+3=8\).

The picture corresponding to the third example:

img

The intersection of two paths is \(3\) (vertices \(2\), \(7\) and \(8\)) and the total length is \(5+5=10\).

The picture corresponding to the fourth example:

img

The intersection of two paths is \(5\)(vertices \(1\), \(2\), \(3\), \(4\) and \(5\)) and the total length is \(6+6=12\).

Solution

题意:给定一棵树,找两组点\((x_1, y_1)\)\((x_2, y_2)\),使得\(x_1,y_1\)不在\(x_2\)\(y_2\)之间的路径上,\(x_2,y_2\)不在\(x_1\)\(y_1\)之间的路径上,要求:

  • \(x_1,y_1\)之间的路径与\(x_2,y_2\)之间的路径的重合边数最多
  • 满足第一个条件的前提下,两条路径的长度之和最大

我们考虑两条路径的公共路径,不妨记作\((x, y)\)\(x\)\(y\)的LCA记作\(a\),则\(a\)或者是\(x\)\(y\)中的一个,或者是\(x\)\(y\)路径上的其他节点,所以我们先求出每个点的度大于2的后代的最大深度,以及每个点往父亲方向能够到达的最远距离,然后再一次DFS,对于任何一个点\(u\)

  • 如果\(u\)有两个孩子节点具有度大于2的后代,则尝试更新答案
  • 否则,若\(u\)只有一个孩子节点具有度大于2的后代,且\(u\)自身的度大于2,则尝试更新答案
#include <bits/stdc++.h> using namespace std; const int maxn = 200011; struct triple { triple(int _u = 0, int _v1 = 0, int _v2 = 0) : u(_u), v1(_v1), v2(_v2) {} int u, v1, v2; bool operator<(const triple &b) const {return u < b.u;} }; vector<int> w[maxn]; int deg[maxn], dep[maxn]; int x1, y1, x2, y2; pair<pair<int, int>, triple> val[maxn]; // <<deg=3的后代(u)的最大深度, u到两个最远后代(v1, v2)的距离之和>, <u, v1, v2>> pair<int, int> ans; pair<int, int> mxdep[maxn], updis[maxn]; // <最远距离, u> vector<pair<pair<int, int>, int>> downdis[maxn]; // <<后代(u)的最大深度, u>, 到该后代的路径上的第一个点> void dfs1(int u, int d, int pre) { dep[u] = d; mxdep[u] = make_pair(d, u); for (int v : w[u]) { if (v == pre) continue; dfs1(v, d + 1, u); mxdep[u] = max(mxdep[u], mxdep[v]); downdis[u].push_back(make_pair(mxdep[v], v)); } sort(downdis[u].begin(), downdis[u].end(), greater<pair<pair<int, int>, int>>()); } void dfs2(int u, int pre) { if (~pre) { updis[u] = make_pair(1 + updis[pre].first, updis[pre].second); auto tp = downdis[pre][0].second == u ? downdis[pre][1].first : downdis[pre][0].first; if (downdis[pre].size() > 1) { updis[u] = max(updis[u], make_pair(tp.first + 1, tp.second)); } } else { updis[u] = make_pair(0, u); } for (int v : w[u]) { if (v == pre) continue; dfs2(v, u); } } void dfs3(int u, int pre) { vector<pair<pair<pair<int, int>, triple>, int>> vec; for (int v : w[u]) { if (v == pre) continue; dfs3(v, u); if (val[v].first.first) { vec.push_back(make_pair(val[v], v)); } } if (vec.size() >= 2) { sort(vec.begin(), vec.end(), greater<pair<pair<pair<int, int>, triple>, int>>()); auto &x = vec[0].first, &y = vec[1].first; val[u] = x; int a = x.first.first + y.first.first - 2 * dep[u]; int b = x.first.second + y.first.second; auto c = make_pair(a, b); if (c > ans) { ans = c; x1 = x.second.v1, y1 = y.second.v1; x2 = x.second.v2, y2 = y.second.v2; } } else { if (vec.size() == 1) { val[u] = vec[0].first; } else if (deg[u] >= 3) { assert(downdis[u].size() >= 2); auto &x = downdis[u][0].first, &y = downdis[u][1].first; int tp = x.first + y.first - 2 * dep[u]; val[u] = make_pair(make_pair(dep[u], tp), triple(u, x.second, y.second)); } else { val[u] = make_pair(make_pair(0, 0), triple()); } if (vec.size() == 1 && deg[u] >= 3) { vector<pair<int, int>> cand; cand.push_back(updis[u]); int up = min(3, (int)downdis[u].size()); for (int i = 0; i < up; ++i) { if (downdis[u][i].second == vec[0].second) continue; cand.push_back(downdis[u][i].first); } assert(cand.size() >= 2); sort(cand.begin(), cand.end(), greater<pair<int, int>>()); auto &x = vec[0].first; int a = x.first.first - dep[u]; int b = x.first.second + cand[0].first + cand[1].first; auto c = make_pair(a, b); if (c > ans) { ans = c; x1 = x.second.v1, y1 = cand[0].second; x2 = x.second.v2, y2 = cand[1].second; } } } } int main() { int n; scanf("%d", &n); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); w[u].push_back(v); w[v].push_back(u); ++deg[u]; ++deg[v]; } ans = make_pair(0, 0); dfs1(1, 0, -1); dfs2(1, -1); dfs3(1, -1); printf("%d %d\n%d %d\n", x1, y1, x2, y2); return 0; }

转载于:https://www.cnblogs.com/hitgxz/p/9977668.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107195.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python破解版激活码【中文破解版】

    (python破解版激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html83PVI25FMO-eyJsaWN…

    2022年3月27日
    75
  • 配置JDK环境变量(最简单手把手教程)

    配置JDK环境变量(最简单手把手教程)​目录简介JDK卸载准备JDK环境配置校检配置简介本文博客只为自己记忆,就新手最简单手把手教程JRE(JavaRuntimeEnvironment)Java运行环境,用来运行

    2022年7月1日
    23
  • xshell 激活成功教程版安转教程

    xshell 激活成功教程版安转教程转自:https://www.cnblogs.com/bowendown/p/11937159.html,亲测perfect!目录一、xshell6商业版安装教程1.为什么要用xshell2

    2022年8月4日
    4
  • 开发微信公众号步骤_微信公众平台开发

    开发微信公众号步骤_微信公众平台开发磨刀不误砍柴工微信公众号大家肯定都用过。目前微信公众号主要分为订阅号和服务号,每种账号又分为未认证和已认证,它们的差别主要在于具有不同的接口权限,下图(引用自微信开发实战系列)是一些例子:不同类型公众号的权限总体来说,服务号权限>订阅号权限,认证账号权限>未认证账号权限。申请订阅号比较简单,服务号相对复杂点,另外要认证的话还要额外提交一些材料。我们可以根据不同的业务需求去申请不同类型的账号,基本上常用的权限列表已经可以满足大部分的场景。开发微信公众号本质上和通常.

    2022年9月28日
    0
  • vue(24)网络请求模块axios使用「建议收藏」

    vue(24)网络请求模块axios使用「建议收藏」什么是axiosAxios是一个基于promise的HTTP库,可以用在浏览器和node.js中。主要的作用:axios主要是用于向后台发起请求的,还有在请求中做更多是可控功能。a

    2022年8月7日
    9
  • SQL使用模糊查询like的优化

    SQL使用模糊查询like的优化 SQL使用模糊查询like’%ABC’和like’%ABC%’的优化 &#1…

    2022年5月11日
    36

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号