林克卡特树
有一棵树,你要选出 \(k+1\) 条点不相交的链,使得它们的长度加起来最大。
\(n \leq 3\times 10^5\)。
题解
DP状态设计:
https://blog.csdn.net/stone41123/article/details/84061375
代码实现:
https://www.cnblogs.com/zwfymqz/p/9163274.html
这题有个尽量多选还是尽量少选的问题。
如果写的是尽量多选的话,会被以下数据卡掉:
11 5
1 2 1
2 3 1
3 4 1
4 5 1
5 6 1
6 7 1
7 8 1
8 9 1
9 10 1
10 11 1
具体原因不清楚,因为带权二分的方案构造很困难。尽量少选就是对的。
考试的时候造个类似的数据两种都试一下就行了。实践是检验真理的唯一标准。
struct node {int x,y;}; // value,number
IN bool operator<(CO node&a,CO node&b){
return a.x!=b.x?a.x to[N];
node dp[N][3];
int mid;
void dfs(int u,int fa){
dp[u][2]=max(dp[u][2],{-mid,1});
for(CO edge&e:to[u])if(e.v!=fa){
dfs(e.v,u);
dp[u][2]=max(dp[u][2]+dp[e.v][0],dp[u][1]+dp[e.v][1]+(node){e.w-mid,1});
dp[u][1]=max(dp[u][1]+dp[e.v][0],dp[u][0]+dp[e.v][1]+(node){e.w});
dp[u][0]=dp[u][0]+dp[e.v][0];
}
dp[u][0]=max(dp[u][0],max(dp[u][1]+(node){-mid,1},dp[u][2]));
}
signed main(){
int n=read(),K=read()+1;
for(int i=1;i(),v=read(),w=read();
to[u].push_back({v,w}),to[v].push_back({u,w});
}
int l=-1e6,r=3e11;
while(l>1;
memset(dp+1,0,n*3*sizeof(node));
dfs(1,0);
if(dp[1][0].y>=K) l=mid;
else r=mid-1;
}
mid=l;
memset(dp+1,0,n*3*sizeof(node));
dfs(1,0);
printf("%lld\n",dp[1][0].x+mid*K);
return 0;
}