八省聯考2018 林克卡特樹

2022-07-13 19:42:14 字數 2770 閱讀 2084

題目描述

小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 能得到的 總收益 - 總過路費最大是多少。

題解

先考慮斷掉k條邊又連上k條邊這個問題,因為最後我們只需要選取最終的樹上的一條鏈,所以我們連上這k條邊相當於是把這條鏈分成k+1段。

所以我們需要找到樹上相互無交的嚴格的k+1條鏈(根據題目描述,乙個點也可以算做一條鏈)。

為什麼要嚴格k+1段呢?因為這k+1段之間不能有交,所以必然會空出k條沒有被選的邊,正好可以留給我們斷邊用。

好了,題目大概分析要這裡,然後dp鏈的問題有乙個經典做法就是揹包,因為不能有交,所以每個點只可能有三種狀態012,表示這個點向下的邊中有幾條被選了,dp時討論一下。

#include#include

#include

#define n 300002

#define m 103

using

namespace

std;

typedef

long

long

ll;ll dp[n][m][3];

inttot,head[n],n,k;

inline ll rd()

while(isdigit(c))

return f?-x:x;

} struct edgee[n<<1

];inline

void add(int u,int v,ll l)

inline ll mx(ll x,ll y,ll z)

void dfs(int u,int

fa) }

}}int

main()

dfs(

1,0);

cout

<1][k+1][2],max(dp[1][k+1][0],dp[1][k+1][1

]));

return0;

}

view code

因為有負邊權的存在,隨著k的增加,答案不一定是嚴格單調遞增的。

但是我們可以發現,答案是乙個上凸函式 。

解決這種問題一般的操作是帶權二分。

在這道題中,我們二分乙個權mid,代表每選擇一條鏈都要付出-mid的代價。

然後按照上面的方法直接按照權值大小貪心的做o(n)的dp。

然後看看最優解選沒選夠k+1條鏈,夠了就加大mid,否則減小mid。

#include#include

#include

#include

#define n 300002

#define m 103

#define inf 1e18

using

namespace

std;

typedef

long

long

ll;int

tot,head[n],n,k;

ll sum,mid,ans;

inline ll rd()

while(isdigit(c))

return f?-x:x;

} struct edgee[n<<1

];inline

void add(int u,int v,ll l)

struct

node

node

operator +(const node &b)const

; }

node

operator +(const ll &b)const

; }

}dp[n][3];

void dfs(int u,int

fa);dp[u][0]=node;dp[u][1]=node;

for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa));

dp[u][

1]=max(dp[u][1]+dp[v][0],dp[u][0]+dp[v][1]+e[i].l);

dp[u][

0]=dp[u][0]+dp[v][0

]; }

dp[u][

0]=max(dp[u][0],max(dp[u][1]+node,dp[u][2

]));

}int

main()

ll l=-sum,r=sum;

while(l<=r)

mid=ans;

dfs(

1,0);

cout

<1][0].val+ans*k;

return0;

}

view code

2018八省聯考 林克卡特樹

題目真滴皮 orz rqy 10分的暴力都沒拿到 10分直接求直徑 60分 容易?想到題目等價於求k 1條不相交的鏈 設狀態f i j 0 1 2 f i j 0 1 2 表示以第i個節點為根的子樹用了j條鏈並且根和兒子連有 0,1,2 條邊。轉移分為5類 g j cc 0 max g j cc 0...

八省聯考2018 林克卡特樹

挺簡單的一道題。原題斷k kk條邊連k kk條邊權為0 00的邊相當於尋去k 1 k 1k 1條不相交鏈出來,將它們連上得到的結果。所以我們要從原樹中選取k 1 k 1k 1條鏈出來,使得它們的權值和最大。我們發現恰好k 1 k 1k 1條鏈這個限制是比較難限制的,考慮通過凸優化二分去進行維護。由於...

八省聯考 2018 林克卡特樹

題意 求乙個凸函式的最優解。思路 好吧在題意裡已經說出來了。對於被卡斜率的,只能 orz 了。其實據說還有 12s 評測這種操作,對不起我省 5s 好吧不廢話了,看看應該怎麼做。暴力的話直接記 dp i j 0 2 表示當前做到第 i 棵子樹用了 j 條鏈並且當前點有 0 2 條出邊,轉移也好想。正...