/*
Problem: Minimum Stones to Balance a Tree
Company Tag: Tower Research OA
Problem Statement:
We are given a tree with n nodes.
stones[i] means initial stones on node i + 1.
In one operation:
We can add 1 stone to any node.
We cannot remove stones.
The tree is balanced if for every edge (u, v):
abs(final[u] - final[v]) <= 1
Also:
final[u] >= stones[u]
Return minimum total stones added.
Constraints:
2 <= n <= 200000
tree_from.length == tree_to.length == n - 1
1 <= tree_from[i], tree_to[i] <= n
0 <= stones[i] <= 1000000000
Input forms a valid tree.
Brute Force:
Try possible final values for every node.
Why Brute Force Fails:
n can be 200000.
stones[i] can be up to 1e9.
Optimized Idea:
For every node u:
final[u] must be large enough because of every other node v.
If node v has stones[v]:
final[u] >= stones[v] - distance(u, v)
So:
final[u] = max over all v of stones[v] - distance(u, v)
This can be computed using rerooting DP.
Explanation Block:
down[u]:
Best requirement coming from subtree of u.
fromParent[u]:
Best requirement coming from parent side and sibling subtrees.
final[u]:
max(down[u], fromParent[u])
Answer:
sum(final[u] - stones[u])
Dry Run:
n = 3
edges:
1 - 2
1 - 3
stones = [1, 1, 10]
Node 3 has 10 stones.
Node 1 is distance 1 from node 3:
node 1 must be at least 9.
Node 2 is distance 2 from node 3:
node 2 must be at least 8.
Final:
node 1 = 9
node 2 = 8
node 3 = 10
Added stones:
8 + 7 + 0 = 15
Time Complexity:
O(n)
Space Complexity:
O(n)
*/
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
long long minimumAddedStones(
int n,
vector<int>& tree_from,
vector<int>& tree_to,
vector<long long>& stones
) {
vector<vector<int>> graph(n + 1);
for (int i = 0; i < n - 1; i++) {
int u = tree_from[i];
int v = tree_to[i];
graph[u].push_back(v);
graph[v].push_back(u);
}
vector<int> parent(n + 1, 0);
vector<int> order;
queue<int> q;
// Root the tree at node 1.
q.push(1);
parent[1] = -1;
while (!q.empty()) {
int u = q.front();
q.pop();
order.push_back(u);
for (int v : graph[u]) {
if (v == parent[u]) {
continue;
}
parent[v] = u;
q.push(v);
}
}
vector<ll> down(n + 1, 0);
// First pass:
// Calculate requirement coming from children/subtree.
for (int i = n - 1; i >= 0; i--) {
int u = order[i];
down[u] = stones[u - 1];
for (int v : graph[u]) {
if (parent[v] == u) {
// If child v needs down[v],
// parent u must be at least down[v] - 1.
down[u] = max(down[u], down[v] - 1);
}
}
}
const ll NEG = -4000000000000000000LL;
vector<ll> fromParent(n + 1, NEG);
// Second pass:
// Send parent-side information to children.
for (int u : order) {
ll best1 = NEG;
ll best2 = NEG;
int bestChild = -1;
// Store top two child contributions.
// This helps when excluding one child's own contribution.
for (int v : graph[u]) {
if (parent[v] == u) {
ll contribution = down[v] - 1;
if (contribution > best1) {
best2 = best1;
best1 = contribution;
bestChild = v;
} else if (contribution > best2) {
best2 = contribution;
}
}
}
for (int v : graph[u]) {
if (parent[v] != u) {
continue;
}
// If v itself gave the best contribution,
// use second best for sibling contribution.
ll bestSibling = (v == bestChild ? best2 : best1);
ll bestAtUWithoutThisChild = stones[u - 1];
// Requirement from parent side.
bestAtUWithoutThisChild = max(bestAtUWithoutThisChild, fromParent[u]);
// Requirement from sibling subtrees.
bestAtUWithoutThisChild = max(bestAtUWithoutThisChild, bestSibling);
// Moving from u to child v increases distance by 1,
// so requirement decreases by 1.
fromParent[v] = bestAtUWithoutThisChild - 1;
}
}
long long ans = 0;
for (int u = 1; u <= n; u++) {
ll finalValue = max(down[u], fromParent[u]);
// We only add stones, so added amount is final - initial.
ans += finalValue - stones[u - 1];
}
return ans;
}
int main() {
int n = 3;
vector<int> tree_from = {1, 1};
vector<int> tree_to = {2, 3};
vector<long long> stones = {1, 1, 10};
cout << minimumAddedStones(n, tree_from, tree_to, stones) << endl;
return 0;
}