#include <bits/stdc++.h>
using namespace std;
/*
Problem: Maximum Weight Forest with Component Size Limit
You are given an undirected weighted tree with n nodes numbered from 0 to n - 1.
Each edge is given as:
[u, v, w]
meaning there is an edge between u and v with weight w.
You are allowed to remove any number of edges.
After removing edges, the tree becomes a forest.
A forest is considered valid if every connected component
has size at most k.
Your task is to return the maximum possible sum of weights
of the edges that remain, such that the resulting forest is valid.
------------------------------------------------------------
Example 1:
n = 3, k = 2
edges = {{0,1,5}, {1,2,10}}
If we keep both edges, all 3 nodes stay connected,
so component size becomes 3, which is not allowed.
We must remove one edge.
Best choice is to keep edge (1,2) with weight 10.
Answer = 10
------------------------------------------------------------
Example 2:
n = 5, k = 2
edges = {{0,1,4}, {1,2,3}, {1,3,7}, {3,4,2}}
We need every connected component to contain at most 2 nodes.
So we remove some edges in a way that keeps as much total weight as possible.
------------------------------------------------------------
Main idea:
This is a tree DP problem.
Let dp[u][s] mean:
- we are only considering the subtree rooted at u
- all connected components inside this subtree are already valid
- the component that contains u currently has exactly s nodes
- dp[u][s] = maximum total weight we can keep inside this subtree
Now process children one by one.
For each child v of u, we have 2 choices:
1) Cut the edge (u, v)
Then v's subtree becomes a separate component.
So we just add the best valid answer from v's subtree.
2) Keep the edge (u, v)
Then the component containing u merges with the component containing v.
If u-part has size s and v-part has size t,
then merged size becomes s + t.
This is allowed only if s + t <= k.
So this becomes a knapsack-style merge on tree DP.
Time Complexity:
Roughly O(n * k^2)
Space Complexity:
O(n * k)
*/
class Solution {
public:
long long maximumKeptWeight(int n, int k, vector<vector<int>>& edges) {
vector<vector<pair<int, int>>> tree(n);
for (auto& e : edges) {
int u = e[0];
int v = e[1];
int w = e[2];
tree[u].push_back({v, w});
tree[v].push_back({u, w});
}
const long long NEG = -(1LL << 60);
// dp[u][s] = best answer for subtree of u,
// when the component containing u has size s
vector<vector<long long>> dp(n);
// subtreeSize[u] = number of nodes in subtree of u
vector<int> subtreeSize(n, 0);
function<void(int, int)> dfs = [&](int u, int parent) {
subtreeSize[u] = 1;
// Initially only node u is present
dp[u] = vector<long long>(2, NEG);
dp[u][1] = 0;
for (auto& [v, w] : tree[u]) {
if (v == parent) continue;
dfs(v, u);
int limitU = min(subtreeSize[u], k);
int limitV = min(subtreeSize[v], k);
// If we cut edge (u, v), then v becomes separate.
// We only need the best valid answer from v's subtree.
long long bestSeparate = NEG;
for (int t = 1; t <= limitV; t++) {
bestSeparate = max(bestSeparate, dp[v][t]);
}
// New DP after processing child v
vector<long long> nextDp(min(subtreeSize[u] + subtreeSize[v], k) + 1, NEG);
for (int s = 1; s <= limitU; s++) {
if (dp[u][s] == NEG) continue;
// Option 1: cut edge (u, v)
// u's component size stays the same
nextDp[s] = max(nextDp[s], dp[u][s] + bestSeparate);
// Option 2: keep edge (u, v)
// merge u's component with v's component
for (int t = 1; t <= limitV && s + t <= k; t++) {
if (dp[v][t] == NEG) continue;
nextDp[s + t] = max(
nextDp[s + t],
dp[u][s] + dp[v][t] + w
);
}
}
subtreeSize[u] += subtreeSize[v];
dp[u].swap(nextDp);
}
};
// Root the tree at node 0
dfs(0, -1);
// At the root, any valid component size is fine
long long answer = 0;
for (int s = 1; s < (int)dp[0].size(); s++) {
answer = max(answer, dp[0][s]);
}
return answer;
}
};