Codeforces Round#769(Div.2)E1+E2 Distance Tree

2024-03-29 14:48

本文主要是介绍Codeforces Round#769(Div.2)E1+E2 Distance Tree,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

树是无环的连通无向图。加权树具有分配给每条边的权重。两个顶点之间的距离是连接它们的路径上的最小权重之和。
给定一棵具有 n 个顶点的加权树,每条边的权重为 1。将 d(v) 表示为顶点 1 和顶点 v 之间的距离。
如果可以在任意两个顶点 a 和 b (1≤a,b≤n) 之间临时添加一条权重为 x 的边,则令 f(x) 为 max{d(v),1<=v<=n} 的最小可能值。请注意,经过此操作后,图不再是树。

对于从 1 到 n 的每个整数 x,求 f(x)。

输入
第一行包含一个整数 t (1≤t≤104)——测试用例的数量。

每个测试用例的第一行包含一个整数 n (2≤n≤3000)。

接下来的 n-1 行中的每一行都包含两个整数 u 和 v (1≤u,v≤n),表示顶点 u 和 v 之间存在一条边。保证给定的边形成一棵树。

保证所有测试用例的 n 总和不超过 3⋅105

输出
对于每个测试用例,在一行中打印 n 个整数,对于从 1 到 n 的所有 x,其中的第 x 个等于 f(x)。

题解

提示:
1.添加类型为 (1,v) 的边是最佳的。
2.尝试检查固定 x 的答案是否最多为 ans。
3.对于固定的 x 和答案 ans,求具有 depthv>ans 的节点之间的距离。
4.对于每个节点,找到两个具有最深子树的子节点。
f a n s f_{ans} fans 为具有 d e p t h v > a n s depth_{v}>ans depthv>ans 的两个节点之间的最大距离。如果对于某些 x 答案最多是 ans,那么 a n s ≥ d e p t h 或 ⌈ f a n s / 2 ⌉ + x ≤ a n s ans≥depth 或 ⌈f_{ans/2}⌉+x≤ans ansdepthfans/2+xans,因为我们可以添加一条边 (1,u),其中 u 位于连接最远的两条路径的中间 d e p t h v > a n s depth_{v}>ans depthv>ans 的节点。由于随着ans的增加 f a n s f_{ans} fans减少,我们可以使用二分搜索。另请注意,我们可以使用两个指针并在增加 x 时增加 ans。

如何计算 f a n s f_{ans} fans?让我们为每个节点找到它的两个具有最深子树的子节点。令 a v a_{v} av 和 b_{v} 为其子树的深度(a_{v}≥b_{v})。如果没有足够的孩子,将此值设置为 d e p t h v depth_{v} depthv。如果 b v > 0 , 做 f b v − 1 : = m a x ( f b v − 1 , a v + b v − 2 ⋅ d e p t h v ) b_v>0,做f_{bv−1}:=max(f{bv−1},a_v+b_v−2⋅depth_{v}) bv>0fbv1:=max(fbv1,av+bv2depthv)。之后,将 i 从 n−2 迭代到 0 并执行 f i = m a x ( f i , f i + 1 ) f_i=max(f_i,f_{i+1}) fi=max(fi,fi+1)

时间复杂度:O(n) 或 O(nlogn),二分查找。
E1:

#include <bits/stdc++.h>
using namespace std;vector<vector<int>> g;
vector<int> depth;
int max_dist;
int corr, curr;void dfs1(int v, int p, int h) {depth[v] = h;for(int to : g[v]) {if(to == p) {continue;}dfs1(to, v, h + 1);}
}void dfs2(int v, int p, int h) {if(h > max_dist && depth[v] > curr) {max_dist = h;corr = v;}for(int to : g[v]) {if(to == p) {continue;}dfs2(to, v, h + 1);}
}int main() {int t;cin >> t;while(t--) {int n;cin >> n;g.assign(n, {});depth.resize(n);for(int i = 0; i < n - 1; ++i) {int u, v;cin >> u >> v;--u, --v;g[u].push_back(v);g[v].push_back(u);}dfs1(0, 0, 0);curr = 0;for(int x = 1; x <= n; ++x) {while(true) {max_dist = -1;corr = -1;for(int i = 0; i < n; ++i) {if(depth[i] <= curr) {continue;}dfs2(i, i, 0);break;}if(corr == -1) {break;}int v = corr;max_dist = -1, corr = -1;dfs2(v, v, 0);if(max_dist > 2 * (curr - x)) {++curr;} else {break;}}cout << curr << ' ';}cout << '\n';}
}

E2:

#include <bits/stdc++.h>
using namespace std;vector<vector<int>> g;
vector<int> d;
int n;int dfs(int v, int p = -1, int cur_d = 0) {int a = cur_d, b = cur_d;for(int u: g[v]) {if(u == p) continue;int s_d = dfs(u, v, cur_d + 1);if(s_d > a) {b = a;a = s_d;} else if(s_d > b) {b = s_d;}}int i = min(a, b) - 1;if(i >= 0) {d[i] = max(d[i], a + b - 2 * cur_d + 1);}return a;
}void solve() {cin >> n;g.assign(n, {});d.assign(n, 0);for(int i = 0; i < n - 1; i++) {int a, b;cin >> a >> b;a--; b--;g[a].push_back(b);g[b].push_back(a);}int m_ans = dfs(0);for(int i = n - 2; i >= 0; i--) d[i] = max(d[i], d[i + 1]);int ans = 0;for(int k = 1; k <= n; k++) {while(ans < m_ans && d[ans] / 2 + k > ans) ans++;cout << ans << ' ';} cout << '\n';
}int main() {int T;cin >> T;while(T--) {solve();}
}

这篇关于Codeforces Round#769(Div.2)E1+E2 Distance Tree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858876

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

226 Invert Binary Tree

//226 Invert Binary Tree//算法思路:主要使用递归算法public class Solution {public TreeNode invertTree(TreeNode root) {//1 出口 空节点if (root==null)return null;//2 递归 调用自己TreeNode left = root.left;TreeNode right = ro

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

Codeforces#295(Div.2)A、B(模拟+BFS)

解题报告链接:点击打开链接 C. 题目链接:点击打开链接 解题思路: 对于给定的字符串,取出现次数最多的字母(可以同时有多个)。由这些字母组成长度为n的字符串,求有多少种组合。最后用数学知识即可。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <climits>

MemSQL Start[c]UP 2.0 - Round 1A(构造)

题目链接:http://codeforces.com/problemset/problem/452/A 解题思路: 打个表暴力查找匹配。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <complex>#include <cstdio>#include <strin