本文主要是介绍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 ans≥depth或⌈fans/2⌉+x≤ans,因为我们可以添加一条边 (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>0,做fbv−1:=max(fbv−1,av+bv−2⋅depthv)。之后,将 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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!