Codeforces round 1045 div2 D. Sliding Tree
题意:
一棵树,每次选择 \(a\),\(b\),\(c\) 满足 \(b\) 和 \(a\),\(c\) 都有边,然后把 \(b\) 除 \(a\) 外的所有两边接到 \(c\) 上。需要把树变为链,求一个最小操作方案的第一次操作。
题目链接https://codeforces.com/contest/2134/problem/D
思路:
链是直径最长的树,所以需要把树转化为链就是让树的直径在每一步都增加,易知每一步最多使直径加一。
做法:
找到直径上度大于 \(2\) 的点,选定一条直径边作为 \(a\), 选取该点作为 \(b\), 选取不在直径上的点作为 \(c\),则直径必加一。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n;
cin >> n;
vector<vector<int>> e(n + 1);
vector<int> d(n + 1);
for(int i = 1; i < n; i++){
int a, b;
cin >> a >> b;
e[a].push_back(b);
e[b].push_back(a);
}
int id = 0;
auto dfs1 = [&](auto&& dfs1, int u, int fa, int dep) -> void {
d[u] = dep;
if(d[id] < d[u])id = u;
for(auto v : e[u]){
if(v == fa)continue;
dfs1(dfs1, v, u, dep + 1);
}
};
dfs1(dfs1, 1, 0, 1);
int a, b, c;
int ma = 0;
auto dfs2 = [&](auto&& dfs2, int u, int fa, int dep) -> int {
int le = 1;
vector<pair<int,int>> temp;
for(auto v : e[u]){
if(v == fa)continue;
int num = dfs2(dfs2, v, u, dep + 1);
temp.push_back({num, v});
le = max(le, num + 1);
}
sort(temp.begin(), temp.end());
if(e[u].size() > 2){
if(dep + le > ma){
//这里可以保证选取的点一定在直径上
ma = le + dep;
a = fa;
b = u;
c = temp[0].second;
}
}
return le;
};
dfs2(dfs2, id, 0, 1);
if(ma == 0)cout << -1 << "\n";
else {
cout << a << " " << b << " " << c << "\n";
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
// pre(1000);
cin >> t;
while(t--)
solve();
}

浙公网安备 33010602011771号