博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

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

题意:求一个凸函数的最优解。。。

思路:

好吧在题意里已经说出来了。

对于被卡斜率的,只能\(orz\)了。。。

其实据说还有\(12s\)评测这种操作,对不起我省\(5s\)

好吧不废话了,看看应该怎么做。

暴力的话直接记\(dp[i][j][0->2]\)表示当前做到第 \(i\) 棵子树用了$ j$ 条链并且当前点有\(0->2\)条出边,转移也好想。。。

正解的话。。。就是二分斜率。。

我们记\(f[i][0->2]\)表示做到$ i $子树并且出边是\(0->2\)个。

然后差分,发现单调凸性质,在函数上二分最优解即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 600010;
inline int read()
{
	int q=0,f=1;char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;ch=getchar();
	}
	while(isdigit(ch)){
		q=q*10+ch-'0';ch=getchar();
	}
	return q*f;
}

struct node
{
	int x;int y;
	inline void max(int a,int b){
		if(x < a||(x == a && y > b)) x = a,y = b;
	}	
}fp[maxn][3];
node dp[maxn];
node fg[3];
node tmp;
int n,m,k,q;

int cnt;
struct edge
{
	int to;
	int nxt;
	int w;
}e[maxn<<4];
int head[maxn];
inline void add(int u,int v,int w){
	e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;e[cnt].w=w;return;
}
const int inf = 0x7fffffff;
inline void dfs(int x,int f){
	fp[x][0].x=0;fp[x][0].y=0;
	//fp[x][0]=(0,0);
	fp[x][1].x=-q;fp[x][1].y=1;
	fp[x][2].x=-inf;fp[x][2].y=0;
	for(int i = head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y != f){
			dfs(y,x);
			for(int j = 0;j < 3; ++j){
				fg[j]=fp[x][j];
			}
			tmp = dp[y];
			for(int j = 0;j < 3; ++j){
				fp[x][j].max(fg[j].x+tmp.x,fg[j].y+tmp.y);
			}
			fp[x][1].max(fg[0].x+fp[y][1].x+e[i].w,fg[0].y+fp[y][1].y);
			fp[x][2].max(fg[1].x+fp[y][1].x+e[i].w+q,fg[1].y+fp[y][1].y-1);
		}
	}
	dp[x]=fp[x][0];
	for(int i = 1;i < 3; ++i){
		dp[x].max(fp[x][i].x,fp[x][i].y);
	}
	return;
}
int ans;
signed main()
{
	n=read(),m=read();
	++m;
	for(int i = 1;i < n; ++i){
		int u=read(),v=read(),w=read();
		add(u,v,w);add(v,u,w);
	}
	int l=-inf,r=inf;
	while(l <= r){
		q=(l + r)>>1;
		dfs(1,0);
		if(dp[1].y <= m){
			ans = q;
			r = q - 1;
		}
		else l = q + 1;
	}
	q = ans;
	dfs(1,0);
	cout<<dp[1].x+m*q<<endl;
	return 0;
}
posted @ 2018-08-08 17:15  Allorkiya  阅读(125)  评论(0编辑  收藏  举报