[BZOJ5252][八省聯考2018]林克卡特樹lct(DP凸優化/WQS二分)

題目:

我是超鏈接

題解:

題目等價於:在樹上選擇k+條不相交的鏈,使其權值和最大。

考慮樹形DP(以下的k均爲k+1)

一個很直觀的想法是用f[i][j]表示第i個節點,子樹中選了j條鏈的最大價值。

但這樣是無法轉移的,因此我們要考慮到根節點的情況,

令f[0/1/2][i][j]表示i號節點的子樹中選了j條鏈,i節點度數爲0/1/2的最大值。

更新的時候分三種情況討論。

但是這樣複雜度是O(N∗K)的,考慮繼續優化。

看到這種帶k限制類的問題,我們嘗試wqs二分

按照套路,我們觀察f數組在不同的k下的最優解,不難發現函數是上凸的。嚴格證明不會,自己意會一下吧。。

按照套路,二分一個邊權,加到每條邊上,我們可以通過控制邊權來控制k的大小。如果邊權都很小,肯定是少選幾條鏈比較優,如果邊權比較大,肯定是多選幾條優。

按照套路,如果我們二分到一個邊權,在這裏恰好選了k條鏈,那麼這種選法就是最優的。

也就是說,我們對於每一條鏈添加上一個mid的代價,用來調控選擇鏈的數量

判斷的時候不需要枚舉k,因此DP一遍的複雜度爲O(N),總複雜度爲O(NlogV)

還有就是這玩意兒二分的邊界比較詭異。。。

引自這個dalao,學習自DP&dalao

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 1e9
#define LL long long 
using namespace std;
const int N=300005;
int tot,nxt[N*2],point[N],v[N*2];LL c[N*2],mid;
struct hh
{
    LL x,y;
    bool operator <(const hh &a) const {return x<a.x;}
    hh operator +(const hh &a) const {return (hh){x+a.x,y+a.y};}
    hh operator +(const int &bl) const {return (hh){x+bl,y};}
}f[3][N];
void addline(int x,int y,LL z)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}
hh add(hh a){return (hh){a.x-mid,a.y+1};}
void dfs(int x,int fa)
{
    for (int i=point[x];i;i=nxt[i])
        if (v[i]!=fa)
        {
            dfs(v[i],x);
            f[2][x]=max(f[2][x]+f[0][v[i]],add(f[1][x]+f[1][v[i]]+c[i]));
            f[1][x]=max(f[1][x]+f[0][v[i]],f[0][x]+f[1][v[i]]+c[i]);
            f[0][x]=f[0][x]+f[0][v[i]];
        }
    f[0][x]=max(f[0][x],max(add(f[1][x]),max(f[2][x],(hh){-mid,1})));
}
int main()
{
    int n;LL K;scanf("%d%lld",&n,&K);K++;
    LL l,r=0;
    for (int i=1;i<n;i++)
    {
        int x,y;LL z;scanf("%d%d%lld",&x,&y,&z);addline(x,y,z);
        r+=abs(z);
    }
    l=-r;
    while (l<=r)
    {
        mid=(l+r)>>1;
        memset(f,0,sizeof(f));
        dfs(1,0);
        if (f[0][1].y<=K) r=mid-1;
        else l=mid+1;
    }
    mid=l;memset(f,0,sizeof(f));
    dfs(1,0);
    printf("%lld",f[0][1].x+K*mid);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章