[2022 杭电多校7 G] Weighted Beautiful Tree

https://acm.hdu.edu.cn/showproblem.php?pid=7215

题意:
给定树以及点花费 \(c_i\) ,点权 \(w_{ni}\) ,边权 \(w_{ei}\) ,我们需要修改点权,使得对于每条边来说, \(min(w_{nui},w_{nvi}) \leq w_{ei} \leq max(w_{nui},w_{nvi})\)
单点修改的花费为 \(c_u \vert w_{nu}-w'_{nu} \vert\) 。问最小花费和。

思路:
对于每条边来说,当前点作为上界还是下界都是独立的,看起来十分不好处理。但是边权是不会改变的,所以我们可以看点权和边权的大小关系来直接确定作为上界还是下界。考虑枚举点权取值,发现点权的只能选择相邻边权或者本身,否则肯定不优。那么我们对子边按边权排个序, 用父边来作为限制(\(dp[u][0/1]\) 代表点 \(u\) 作为父边的下界 / 上界),这样能保证返回时对上面的贡献是正确的。注意边权相同的边需要一起处理,因为上界下界都有可能,所以要对 \(dp[v][0/1]\) 取小。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;

vector< pair<int, int> > G[N];
ll dp[N][2];
int c[N], w[N];
int n;

ll calc(int u, int v, int w) {
    return 1ll * c[u] * abs(v - w);
}

void dfs(int u, int fa, int ew) {
    ll pre = 0, suf = 0;
    dp[u][0] = dp[u][1] = INF;
    vector< pair<int, int> > sons;
    for (auto &p : G[u]) {
        int v = p.first, nw = p.second;
        if (v == fa) continue;
        dfs(v, u, nw);
        sons.emplace_back(nw, v);
        suf += dp[v][1];
    }
    sons.emplace_back(w[u], 0);
    if (u != 1) sons.emplace_back(ew, 0);
    sort(sons.begin(), sons.end());
    for (int i = 0; i < sons.size(); ++i) {
        int j = i;
        suf -= dp[ sons[j].second ][1];
        ll add = min(dp[ sons[j].second ][0], dp[ sons[j].second ][1]);
        while (j < (int)sons.size() - 1 && sons[j + 1].first == sons[j].first) {
            j++;
            suf -= dp[ sons[j].second ][1];
            add += min(dp[ sons[j].second ][0], dp[ sons[j].second ][1]);
        }
        add += pre + suf;

        if (sons[j].first <= ew || u == 1) {
            dp[u][0] = min(dp[u][0], add + calc(u, w[u], sons[j].first));
        }

        if (sons[j].first >= ew || u == 1) {
            dp[u][1] = min(dp[u][1], add + calc(u, w[u], sons[j].first));
        }
        
        while (i < j) {
            pre += dp[ sons[i].second ][0];
            i++;
        }
        pre += dp[ sons[i].second ][0];
    }
}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        G[i].clear();
    }
    for (int i = 1; i <= n; ++i) cin >> c[i];
    for (int i = 1; i <= n; ++i) {
        cin >> w[i];
    }
    for (int i = 1, u, v, w; i < n; ++i) {
        cin >> u >> v >> w;
        G[u].emplace_back(v, w);
        G[v].emplace_back(u, w);
    }
    dfs(1, 0, 0);
    cout << min(dp[1][0], dp[1][1]) << '\n';
}

int main() {
#ifndef stff577
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(20);
#endif
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}
posted @ 2022-08-11 11:06  stff577  阅读(79)  评论(0编辑  收藏  举报