CF1822F Gardening Friends

题目链接

题解

知识点:树的直径,枚举。

考虑一个结论:树上任意点的最远点一定是树的直径的端点。

那么对于一个根节点,只要知道了树的直径,那么我们就可以立即得到最远距离,即乘 \(k\) 树的价值。

接下来,我们只需要枚举每个点作为根节点时树的价值,减去 \(1\) 转移到这个点的距离乘 \(c\) 即可。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

vector<int> g[200007];

void dfs(int u, int fa, vector<int> &dis) {
    for (auto v : g[u]) {
        if (v == fa) continue;
        dis[v] = dis[u] + 1;
        dfs(v, u, dis);
    }
}

bool solve() {
    int n, k, c;
    cin >> n >> k >> c;
    for (int i = 1;i <= n;i++) g[i].clear();
    for (int i = 1;i <= n - 1;i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<int> dis1(n + 1);
    dfs(1, 0, dis1);
    int A = max_element(dis1.begin() + 1, dis1.end()) - dis1.begin();

    vector<int> disA(n + 1);
    dfs(A, 0, disA);
    int B = max_element(disA.begin() + 1, disA.end()) - disA.begin();

    vector<int> disB(n + 1);
    dfs(B, 0, disB);

    ll ans = 0;
    for (int i = 1;i <= n;i++) ans = max(ans, 1LL * max(disA[i], disB[i]) * k - 1LL * dis1[i] * c);
    cout << ans << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}
posted @ 2023-09-08 09:45  空白菌  阅读(13)  评论(0编辑  收藏  举报