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

题链

分析

可以看做取K+1不相交的链连起来最长
显然可以树形DP,f[i][0/1/2]表示i点度数为0,1,2的个数
\(nK^2\)转移即可
考虑优化,发现取且只取K个,(k,f[K])大胆猜测是凸函数,WQS二分
二分斜率,求交点,可以发现F=kx+b使得b最大
移项:b=F-kx,不妨将所有答案减去kx,变成求最大值问题,这可以DP解决
注意是每条链减去k,而不是每条边减去k,在链底减即可
注意斜率一定是整数

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
const ll INF=1e18;
using namespace std;

const int N=3e5+5,maxk=105;
int n,K,sz[N];
struct A{int v; ll w; }f[N][3],tmp[3];
vector<A>V[N];
A operator +(A i,A j) {
	return (A){i.v+j.v,i.w+j.w};
}
A Max(A i,A j) {
	if(i.w>j.w) return i;
	if(i.w<j.w) return j;
	if(i.v<j.v) return i;
	return j;
}
ll m;
void dfs(int fa,int u) {
	f[u][0]=(A){0,0},f[u][1]=(A){1,-m},f[u][2]=(A){1,-m};
	for(A v:V[u]) {
		if(v.v!=fa) {
			dfs(u,v.v);
			tmp[0]=f[u][0],tmp[1]=f[u][1],tmp[2]=f[u][2];
			f[u][0]=Max(f[u][0],tmp[0]+f[v.v][0]);
			f[u][1]=Max(f[u][1],Max(tmp[1]+f[v.v][0],tmp[0]+f[v.v][1]+(A){0,v.w}));
			f[u][2]=Max(f[u][2],Max(tmp[1]+f[v.v][1]+(A){-1,v.w+m},tmp[2]+f[v.v][0]));
		}
	}
	f[u][0]=Max(f[u][0],Max(f[u][1],f[u][2]));
}

bool check(ll mid) {
	m=mid;
	dfs(0,1);
	return f[1][0].v<=K;
}
int main() {
//	freopen("1.in","r",stdin);
	scanf("%d%d",&n,&K); K++;
	if(n==K) {
		cout<<0<<endl;
	}
	for(int i=1;i<n;i++) {
		int u,v,k; scanf("%d%d%d",&u,&v,&k);
		V[u].pb((A){v,k}),V[v].pb((A){u,k});
	}
	ll l=-3e11,r=3e11,mid,ans;
	while(l<=r) {
		mid=l+r>>1;
		if(check(mid)) {
			ans=mid,r=mid-1;
		} else l=mid+1;
	}
	check(ans);
	cout<<f[1][0].w+ans*K<<endl;
	return 0;
}
posted @ 2021-06-11 23:13  wwwsfff  阅读(45)  评论(0编辑  收藏  举报