码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForces 1073F Choosing Two Paths

时间:2018-11-18 14:11:08      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:long   tput   out   .com   rect   auto   def   code   ati   

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:

技术分享图片

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:

技术分享图片

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:

技术分享图片

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:

技术分享图片

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;
}

CodeForces 1073F Choosing Two Paths

标签:long   tput   out   .com   rect   auto   def   code   ati   

原文地址:https://www.cnblogs.com/hitgxz/p/9977668.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!