【CF】Day84——Codeforces Round 862 (Div. 2) D (⭐树的直径的性质 + DFS找树的直径)

D. A Wide, Wide Graph

题目:

【CF】Day84——Codeforces Round 862 (Div. 2) D (⭐树的直径的性质 + DFS找树的直径)_第1张图片思路:

考察树的直径的性质以及逆向思维

这一题要是正向思考可能会有些难,我们不如反向思考看看

树上的最长路线是树的直径,也就是说如果 k 大于了直径 d,那么所有点都将是一个联通块,否则肯定会有点连接起来

如果我们知道树的直径的性质那么这题就迎刃而解了

对于树的直径的两个端点 u,v,树上任意一点 z 的最长路径其终点一定在 u 或者 v 上

那么只要知道了这个,我们就好做了,既然要满足两点间的距离大于等于 k,那么肯定是取最大值看,由于最大值一定会连接到直径两端任意一个,那么只要 z 对于 u,v 两点的距离大于等于 k,那么就会和 u,v 一起变成一个连通块,并且最后的形态肯定是 一个连通块 和 x 个单点

为什么呢?感性的想,既然 z 到 u,v 的距离最大,那么肯定是先连 u,v,如果有别的节点 y,那么肯定会一起到 u,v 中,即不可能存在先连接 y 再连接 u,v 的情况

所以我们可以用三次dfs来解决这题,前两次求直径的两个端点,同时求每个节点到端点 1 的距离,第三次我们求所有点到端点 2 的距离,最后模拟即可

代码:

#include 
#include 
#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

void solve()
{
    int n;
    cin >> n;
    vector> g(n + 1);
    for (int i = 0; i < n-1; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    vector dep(n + 1, 0),dep2(n+1,0),dep3(n+1,0);
    int root1 = 0, root2 = 0;
    auto dfs1 = [&](auto self, int fa, int se) ->void {
        dep[se] = dep[fa] + 1;
        for (auto& son : g[se])
        {
            if (son == fa) continue;
            self(self, se, son);
        }
        if (dep[se] > dep[root1])
        {
            root1 = se;
        }
        };
    dfs1(dfs1, 1, 1);
    auto dfs2 = [&](auto self, int fa, int se) ->void {
        dep2[se] = dep2[fa] + 1;
        for (auto& son : g[se])
        {
            if (son == fa) continue;
            self(self, se, son);
        }
        if (dep2[se] > dep2[root2])
        {
            root2 = se;
        }
        };
    dfs2(dfs2, root1, root1);
    auto dfs3 = [&](auto self, int fa, int se) ->void {
        dep3[se] = dep3[fa] + 1;
        for (auto& son : g[se])
        {
            if (son == fa) continue;
            self(self, se, son);
        }
        };
    dfs3(dfs3, root2, root2);
    vector dis(n + 1, -1e9);
    for (int i = 1; i <= n; i++)
    {
        dis[i] = max(dep2[i], dep3[i]) - 1;
    }
    sort(dis.begin(), dis.end());
    vector ans;
    int index = n;
    int nowans = n;
    int k = n;
    int flag = 0;
    while (k>0)
    {
        while (index > 0 && dis[index] >= k)
        {
            index--;
            nowans--;
            flag = 1;
        }
        ans.push_back(nowans+ flag);
        k--;
    }
    for (int i = n-1; i >= 0; i--)
    {
        cout << ans[i] << " ";
    }
    cout << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

你可能感兴趣的:(深度优先,算法)