CodeForces 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:
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的更多相关文章
- [codeforces 293]B. Distinct Paths
[codeforces 293]B. Distinct Paths 试题描述 You have a rectangular n × m-cell board. Some cells are alrea ...
- Codeforces 219D. Choosing Capital for Treeland (树dp)
题目链接:http://codeforces.com/contest/219/problem/D 树dp //#pragma comment(linker, "/STACK:10240000 ...
- Codeforces 219D Choosing Capital for Treeland
http://codeforces.com/problemset/problem/219/D 题目大意: 给出一棵树,但是它的边是有向边,选择一个城市,问最少调整多少条边的方向能使一个选中城市可以到达 ...
- (纪念第一道完全自己想的树DP)CodeForces 219D Choosing Capital for Treeland
Choosing Capital for Treeland time limit per test 3 seconds memory limit per test 256 megabytes inpu ...
- CodeForces 219D Choosing Capit
题目链接:http://codeforces.com/contest/219/problem/D 题目大意: 给定一个n个节点的数和连接n个节点的n - 1条有向边,现在要选定一个节点作为起始节点,从 ...
- Codeforces 219D - Choosing Capital for Treeland(树形dp)
http://codeforces.com/problemset/problem/219/D 题意 给一颗树但边是单向边,求至少旋转多少条单向边的方向,可以使得树上有一点可以到达树上任意一点,若有多个 ...
- 【CodeForces】870 F. Paths
[题目]F. Paths [题意]给定数字n,图上有编号为1~n的点,两点当且仅当gcd(u,v)≠1时有连边,定义d(u,v)为两点间最短距离(若不连通则为0),求Σd(u,v),1<=u&l ...
- Codeforces 219D Choosing Capital for Treeland:Tree dp
题目链接:http://codeforces.com/problemset/problem/219/D 题意: 给你一棵树,n个节点. 树上的边都是有向边,并且不一定是从父亲指向儿子的. 你可以任意翻 ...
- Codeforces 643G - Choosing Ads(线段树)
Codeforces 题目传送门 & 洛谷题目传送门 首先考虑 \(p>50\) 的时候怎么处理,也就是求一个区间的绝对众数.我们知道众数这个东西是不能用线段树直接维护的,因为对于区间 ...
随机推荐
- 【爬坑】运行 Hadoop 的 MapReduce 示例卡住了
1. 问题说明 在以伪分布式模式运行 Hadoop 自带的 MapReduce 示例,卡在了 Running job ,如图所示 2. 解决过程 查看日志没得到有用的信息 再次确认配置信息没有错误信息 ...
- <button>与<input type="button">
在做form表单,点击按钮随机生成两串密钥的时候 1.用第一种按钮的时候,会出现刷新form表单的现象.会把创建密钥前面的输入框中的字消失.虽然能生成密钥1和密钥2,但是会闪一下,随即消失.几个输入框 ...
- php框架安装
安装yii框架 跳转到composer.phar目录 cd C:\ProgramData\ComposerSetup\bin 安装yii2高级版 php composer.phar create-pr ...
- [python]关于列表增加元素的几种操作
1.insert方法,该方法包含两个参数,第一个参数为插入的位置参数,第二个参数为插入内容 a = [0,0,0] b = [1,2,3] a.insert(0,b) print a 输出: [[1, ...
- JSONP跨域和CORS跨域
什么是跨域? 跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制! 同源策略 同源策略:域名.协议.端口均相同. 浏览器执行JavaScript脚本时,会检查这 ...
- react-navigation 使用笔记 持续更新中
目录 基本使用(此处基本使用仅针对导航头部而言,不包含tabbar等) header怎么和app中通信呢? React-Navigation是目前React-Native官方推荐的导航组件,代替了原用 ...
- Python glob.md
glob 即使glob API非常简单, 但这个模块包含了很多的功能. 在很多情况下, 尤其是你的程序需要寻找出文件系统中, 文件名匹配特定模式的文件时, 是非常有用的. 如果你需要包含一个特定扩展名 ...
- runloop是iOS系统上的actor模式
runloop是iOS系统上的actor模式(单线程派发的)
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- ThreadLocal解决SimpleDateFormat多线程安全问题中遇到的困惑
测试代码: public class Main { public static void main(String[] args) { for (int k = 0; k < 10; k++) { ...