題意
給你一棵有根樹,每條邊都有一個權值。有一種操作,可以讓某條邊的權值+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;
}