zoukankan      html  css  js  c++  java
  • 林克卡特树

    /*
    林克卡特树
    首先题目可以转化为 ,从一棵树种选择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
    */
  • 相关阅读:
    【HDOJ】3660 Alice and Bob's Trip
    【HDOJ】3652 B-number
    【HDOJ】4057 Rescue the Rabbit
    【HDOJ】2155 小黑的镇魂曲
    【HDOJ】2828 Lamp
    【HDOJ】3275 Light
    【HDOJ】2430 Beans
    【POJ】2823 Sliding Window
    CE下可用的3G
    RIL开发过程
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/9152865.html
Copyright © 2011-2022 走看看