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();
}
posted @ 2025-09-08 11:09  DUC27  阅读(16)  评论(0)    收藏  举报