/* 林克卡特树 首先题目可以转化为 ,从一棵树种选择k + 1条链,使得这些链上边权总和最大 可以用 dp来做,让每个点对应其父边,dp[i][j][k]表示第j个点度数为i(0, 1, 2),子树种选择了k个链的最优解 这个我只能用NKK复杂度来解,因为每个点要枚举这个点选择链的个数和所有孩子 选择链的个数(但是这个经过分析复杂度是NK ?????) 好吧我们不去管他, 我们要想的是 通过WQS二分去掉k的限制,这样每次就是严格On的了 于是我们二分C,使得每多划分一条链都多花费C,找到恰好合适的即可 至于树形dp的细节以及具体实现 我不想讲。。。 */ #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define M 300100 #define ll long long using namespace std; struct Edge{ ll vj, ver,nxt; }edge[M << 1]; ll head[M], cnt, n, k; ll L,R,mid,ans; void push(int vi, int vj, int ver){cnt++; edge[cnt].vj = vj; edge[cnt].nxt = head[vi], head[vi] = cnt; edge[cnt].ver = ver;} struct Note{ ll a,b; bool operator < (const Note &B) const {return a == B.a ? b > B.b : a < B.a; } // 这里很奇怪 考虑最优解的最大分块情况 Note operator + (const Note &B){return (Note){this->a + B.a, this->b + B.b};} Note operator + (const int &B){return (Note){this->a + B, this->b};} }dp[3][M]; Note w(Note x) {return (Note){x.a - mid,x.b + 1};} ll read(){ ll nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c -'0'; return nm * f; } void dfs(int now, int fa) { dp[2][now] = max(dp[2][now],(Note){-mid, 1}); //cout << max(dp[2][1], dp[2][2]).a; for(int i = head[now]; i; i = edge[i].nxt) { int vj = edge[i].vj; if(vj == fa) continue; dfs(vj, now); dp[2][now] = max(dp[2][now] + dp[0][vj], w((dp[1][now] + dp[1][vj] + edge[i].ver))); dp[1][now] = max(dp[1][now] + dp[0][vj], (dp[0][now] + dp[1][vj] + edge[i].ver)); dp[0][now] = dp[0][now] + dp[0][vj]; } dp[0][now] = max(dp[0][now], max(w(dp[1][now]), dp[2][now])); } int main() { n = read(), k = read() + 1; for(int i = 1; i < n; i++) { ll vi = read(), vj = read(), ver = read(); push(vi, vj, ver);push(vj, vi, ver); if(ver >= 0) R += ver; else R -= ver; } L = -R; while(L <= R) { mid = (L + R) >> 1; memset(dp, 0, sizeof(dp)); dfs(1, 0); if(dp[0][1].b <= k) R = mid - 1, ans = dp[0][1].a; else L = mid + 1; // cout << mid << " " << dp[0][1].a << " "; } mid = R + 1; memset(dp, 0, sizeof(dp)); dfs(1, 0); // cout << L << " ! " << dp[0][1].b; cout << dp[0][1].a + (R + 1) * k; // cout << dp[0][1][k] + dp[0][1][k]; return 0; }/* 5 3 1 2 1 2 3 -1 3 4 1 4 5 -1 */