挺簡單的一道題。
原題斷k
kk條邊連k
kk條邊權為0
00的邊相當於尋去k+1
k+1k+
1條不相交鏈出來,將它們連上得到的結果。
所以我們要從原樹中選取k+1
k+1k+
1條鏈出來,使得它們的權值和最大。
我們發現恰好k+1
k+1k+
1條鏈這個限制是比較難限制的,考慮通過凸優化二分去進行維護。
由於鏈選取的條數關於貢獻的函式一定是乙個凸包,我們可以去二分通過選取k
kk條鏈的點的切線的斜率,來進行判斷。
我們將每條路徑的貢獻減去當前的二分值,再直接用二分去選取不限量的路徑,使得權值最大。
若dp出來的選取鏈數大於k
kk,則說明我們當前二分的值大了,否則就說明小了,只有當選取剛好k
kk條路徑時才能說明我們二分的值是恰當的。
關於這個dp,就是個簡單的樹dp,在樹上找鏈,相信大家都會。
總時間複雜度o(n
logn
)o\left(nlog\,n\right)
o(nlog
n)。
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
#define maxn 300005
#define lowbit(x) (x&-x)
#define reg register
typedef
long
long ll;
typedef
unsigned
long
long ull;
typedef pair<
int,
int> pii;
const ll inf=
0x7f7f7f7f7f7f
;const
int mo=
1e9+7;
const
double pi=
acos(-
1.0)
;template
<
typename _t>
_t fabs
(_t x)
template
<
typename _t>
void
read
(_t &x)
while
('0'
<=s&&s<=
'9')
x*=f;
}int n,k,head[maxn]
,tot;ll dif;
struct edgee[maxn<<1]
;void
addedge
(int u,
int v,ll w)
;head[u]
=tot;
}struct ming;}
friend
bool
operator
<
(const ming &x,
const ming &y)
}dp[maxn][3
];ming max
(ming x,ming y)
void
dosaka
(int u,
int fa));
dp[u][1
]=max(dp[u][1
]+dp[v][0
],dp[u][0
]+dp[v][1
]+(ming));
dp[u][0
]=dp[u][0
]+dp[v][0
];} dp[u][0
]=max(dp[u][0
],max(dp[u][2
],dp[u][1
]+(ming)))
;}ll sakura
(const ll mid)
,dp[i][2
]=(ming)
; dif=mid;
dosaka(1
,0);
return dp[1]
[0].num;
}signed
main()
ll l=
-sum,r=sum;
while
(lll tmp=
sakura
(l);
printf
("%lld"
,dp[1]
[0].sum+
1ll*
(k+1
)*l)
;return0;
}
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 林克卡特樹
題意 求乙個凸函式的最優解。思路 好吧在題意裡已經說出來了。對於被卡斜率的,只能 orz 了。其實據說還有 12s 評測這種操作,對不起我省 5s 好吧不廢話了,看看應該怎麼做。暴力的話直接記 dp i j 0 2 表示當前做到第 i 棵子樹用了 j 條鏈並且當前點有 0 2 條出邊,轉移也好想。正...
八省聯考2018 林克卡特樹
題目描述 小l 最近沉迷於塞爾達傳說 荒野之息 the legend of zelda breath of the wild 無法自拔,他尤其喜歡遊戲中的迷你挑戰。遊戲中有乙個叫做 lct 的挑戰,它的規則是這樣子的 現在有乙個n 個點的 樹 tree 每條邊有乙個整數邊權vi 若vi 0,表示走這...