1. 程式人生 > >[loj 2478][luogu P4843]「九省聯考 2018」林克卡特樹

[loj 2478][luogu P4843]「九省聯考 2018」林克卡特樹

遊戲 for legend tps reat 簡單 block math pap

傳送門

Description

小L 最近沈迷於塞爾達傳說:荒野之息(The Legend of Zelda: Breath of The Wild)無法自拔,他尤其喜歡遊戲中的迷你挑戰。

遊戲中有一個叫做“LCT” 的挑戰,它的規則是這樣子的:現在有一個N 個點的 樹(Tree),每條邊有一個整數邊權vi ,若vi >= 0,表示走這條邊會獲得vi 的收益;若vi < 0 ,則表示走這條邊需要支付- vi 的過路費。小L 需要控制主角Link 切掉(Cut)樹上的 恰好K 條邊,然後再連接 K 條邊權為 0 的邊,得到一棵新的樹。接著,他會選擇樹上的兩個點p; q ,並沿著樹上連接這兩點的簡單路徑從p 走到q ,並為經過的每條邊支付過路費/ 獲取相應收益。

海拉魯大陸之神TemporaryDO 想考驗一下Link。他告訴Link,如果Link 能切掉 合適的邊、選擇合適的路徑從而使 總收益 - 總過路費最大化的話,就把傳說中的大師之劍送給他。

小 L 想得到大師之劍,於是他找到了你來幫忙,請你告訴他,Link 能得到的 總收益 - 總過路費最大是多少。

Solution

原題轉化為樹上求K+1條不相交路徑的最大權值和

是一道WQS二分裸題

首先,可以很容易的寫出一個樹形dp

然後根據wqs的套路,給每條路徑的權值和+add

在計算最大權值和時,我們應當考慮讓選到的邊數盡可能的大

其實就是在寫樹d的時候適當註意一下順序就行

然後,WQS二分出的應該時最小的——使得所選點數\(\geq K+1\)

的add


Code?

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const ll inf=3e11,MN=3e5+5;
int N,K,hr[MN],en;
struct edge{int to;ll w;int nex;}e[MN<<1];
inline void ins(int f,int t,int w)
{
    e[++en]=(edge){t,w,hr[f]};hr[f]=en;
    e[++en]=(edge){f,w,hr[t]};hr[t]=en;
}
ll ans,dec;
struct dp{
    ll v;int c;
    dp(ll _v=0,ll _c=0):v(_v),c(_c){}
    dp operator+(const dp o){return dp(v+o.v,c+o.c);}
    dp operator-(const dp o){return dp(v-o.v,c-o.c);}
    dp operator*(const dp o){return dp(v+o.v-dec,c+o.c-1);}
    dp operator+(const ll o){return dp(v+o,c);}
}f[MN][3];
dp Max(dp o,dp oo){if(o.v>oo.v)return o;return oo;}
void dfs(int x,int fa)
{
    register int i;
        
    for(i=hr[x];i;i=e[i].nex)if(fa^e[i].to)
    {
        dfs(e[i].to,x);
        f[x][2]=Max(f[x][2]+f[e[i].to][0],f[x][1]+f[e[i].to][1]+dp(e[i].w-dec,-1));
        f[x][1]=Max(f[x][0]+f[e[i].to][1]+e[i].w,f[x][1]+f[e[i].to][0]);
        f[x][0]=f[x][0]+f[e[i].to][0];
    }
    f[x][0]=Max(f[x][0],Max(f[x][1],f[x][2]));
}
inline void check(ll mid)
{
    register int i;dec=mid;
    for(i=1;i<=N;++i) f[i][0]=dp(0,0),f[i][2]=f[i][1]=dp(dec,1);
    dfs(1,0);
}
int main()
{
    N=read();K=read()+1;
    register int i,x,y;
    for(i=1;i<N;++i) x=read(),y=read(),ins(x,y,read());
    ll l=-inf,r=inf,mid;
    for(;l<=r;f[1][0].c>=K?r=mid-1:l=mid+1)
    {
        mid=(l+r)>>1;check(mid);
        if(f[1][0].c>=K)ans=f[1][0].v-1ll*f[1][0].c*mid;
    }
    return 0*printf("%lld\n",ans);
}



Blog來自PaperCloud,未經允許,請勿轉載,TKS!

[loj 2478][luogu P4843]「九省聯考 2018」林克卡特樹