LuoguP1131

題意

給你一棵有根樹,每條邊都有一個權值。有一種操作,可以讓某條邊的權值+1。問最少操作多少次,可以讓根到所有葉子節點的路徑長度都相等。

思路

首先能夠想到的是,最終所有路徑都是初始時路徑最長的長度。而且,對於每一棵子樹,對其離根越近的邊使用該操作一定會比對子樹中的邊使用更加合算。所以對於條邊,可以加的權值的最大值爲,子樹的葉子中路徑最大的值,離最終答案的差值。
可以用dfs+線段樹維護子樹中的最大值,同時線段樹還應支持區間修改操作,對每條邊加權值子樹中所有點的值也都增加。

代碼
//
// Created by yjq on 2019/10/5.
//

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define ld long double
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

#define int long long
const int maxn = 10e5 + 10;
int n, root, dfs_r[maxn * 2], cnt, head[maxn], ct;
int l[maxn], r[maxn];
ll final_time;
struct pxy {
    int to, next;
    ll vi;
} e[maxn * 2];

namespace tree {
    struct line {
        int left, right;
        ll maxm, add;
    } c[maxn << 2];

    void build(int id, int l, int r) {
        c[id].left = l;
        c[id].right = r;
        if (l == r)return;
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
    }

    void pushdown(int id) {
        c[id << 1].add += c[id].add;
        c[id << 1].maxm += c[id].add;
        c[id << 1 | 1].add += c[id].add;
        c[id << 1 | 1].maxm += c[id].add;
        c[id].add = 0;
    }

    void update(int id, int l, int r, ll v) {
        if (c[id].left > r || c[id].right < l)return;
        if (c[id].left >= l && c[id].right <= r) {
            c[id].add += v;
            c[id].maxm += v;
            return;
        }
        if (c[id].add)pushdown(id);
        update(id << 1, l, r, v);
        update(id << 1 | 1, l, r, v);
        c[id].maxm = max(c[id << 1].maxm, c[id << 1 | 1].maxm);
    }

    ll query_max(int id, int l, int r) {
        if (c[id].add)pushdown(id);
        if (c[id].left == l && c[id].right == r)return c[id].maxm;
        int mid = (c[id].left + c[id].right) >> 1;
        if (r <= mid)return query_max(id << 1, l, r);
        else if (l > mid)return query_max(id << 1 | 1, l, r);
        else return max(query_max(id << 1, l, mid), query_max(id << 1 | 1, mid + 1, r));
    }
}

void ins(int x, int y, int z) {
    e[++cnt].to = y;
    e[cnt].next = head[x];
    e[cnt].vi = z;
    head[x] = cnt;
}

void dfs(int x, ll s, int fa) {
    dfs_r[++ct] = x;
    l[x] = ct;
    for (int i = head[x]; i; i = e[i].next) {
        if (e[i].to != fa) {
            dfs(e[i].to, s + e[i].vi, x);
        }
    }
    dfs_r[++ct] = x;
    r[x] = ct;
    if (l[x] == r[x] - 1) {
        final_time = max(final_time, s);
        tree::update(1, l[x], r[x], s);
    }
}

ll dp(int x, int fa) {
    ll ans = 0;
    for (int i = head[x]; i; i = e[i].next) {
        if (e[i].to != fa) {
            ll t = tree::query_max(1, l[e[i].to], r[e[i].to]);
            ans += final_time - t;
            tree::update(1, l[e[i].to], r[e[i].to], final_time - t);
            ans += dp(e[i].to, x);
        }
    }
    return ans;
}

main() {
    __;
    cin >> n >> root;
    for (int i = 1; i < n; ++i) {
        int x, y, z;
        cin >> x >> y >> z;
        ins(x, y, z);
        ins(y, x, z);
    }
    tree::build(1, 1, n * 2);
    dfs(root, 0, -1);
    cout << dp(root, -1) << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章