fastle
垆边人似月 皓腕凝霜雪
/*
林克卡特树
首先题目可以转化为 ,从一棵树种选择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 << "\n";
    }
    mid = R + 1;
    memset(dp, 0, sizeof(dp));
    dfs(1, 0);
//    cout << L << " !\n" << 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
*/

 

posted on 2018-06-07 21:23  fastle  阅读(319)  评论(0编辑  收藏  举报