[八省联考2018]林克卡特树

CXLI.[八省联考2018]林克卡特树

一眼发现函数是凸的。然后思考发现直接一个树形DP就能进行二分的check:设 fi,0/1/2 分别表示节点 i,其中 i 未被选/是一条链的链顶/被一条链经过,然后直接DP就行。

为什么二分边界要开到 1012

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,g[300100][3],head[300100],cnt;
ll f[300100][3],ip;//0:x is on nothing 1:x is currently on a path 2:x's path has been matched
struct node{int to,next,val;}edge[600100];
void ae(int u,int v,int w){
	edge[cnt].next=head[u],edge[cnt].to=v,edge[cnt].val=w,head[u]=cnt++;
	edge[cnt].next=head[v],edge[cnt].to=u,edge[cnt].val=w,head[v]=cnt++;
}
void trans(ll &F,int &G,ll ff,int gg){
	if(F<ff)F=ff,G=gg;
	else if(F==ff)G=min(G,gg);
}
void dfs(int x,int fa){
	f[x][0]=f[x][1]=f[x][2]=0,g[x][0]=g[x][1]=g[x][2]=0;
	for(int i=head[x],y,z;i!=-1;i=edge[i].next){
		y=edge[i].to,z=edge[i].val;
		if(y==fa)continue;
		dfs(y,x);
		
		f[x][2]+=f[y][2],g[x][2]+=g[y][2];
//		printf("%d,%d:%d,%d,%d,%d\n",x,y,f[x][1],f[y][1],z,-ip);
		trans(f[x][2],g[x][2],f[x][1]+f[y][1]+z-ip,g[x][1]+g[y][1]+1);
		
		f[x][1]+=f[y][2],g[x][1]+=g[y][2];
		
		trans(f[x][1],g[x][1],f[x][0]+f[y][1]+z,g[x][0]+g[y][1]);
		
		f[x][0]+=f[y][2],g[x][0]+=g[y][2];
	}
	trans(f[x][2],g[x][2],f[x][1]-ip,g[x][1]+1);
	trans(f[x][2],g[x][2],f[x][0],g[x][0]);
//	printf("%d:\n%d %d %d\n%d %d %d\n",x,f[x][0],f[x][1],f[x][2],g[x][0],g[x][1],g[x][2]);
}
int main(){
	scanf("%d%d",&n,&m),m++,memset(head,-1,sizeof(head));
	for(int i=1,x,y,z;i<n;i++)scanf("%d%d%d",&x,&y,&z),ae(x,y,z);
	ll l=-1e12,r=1e12;
	while(l<r){
		ip=(l+r)>>1;
//		printf("%d------------\n",ip); 
		dfs(1,0);
		if(g[1][2]<=m)r=ip;
		else l=ip+1;
	}
	ip=l,dfs(1,0);
	printf("%lld\n",f[1][2]+1ll*l*m);
	return 0;
}

posted @   Troverld  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示