ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)

2020-05-06 19:59:52  阅读:273  来源: 互联网

标签:二分 八省 ch wqs dtmp qm 联考 dp


uoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)

Luogu

题解时间

$ k $ 条边权为 $ 0 $ 的边。

是的,边权为零。

转化成选正好 $ k+1 $ 条链。

$ k \le 100 $ 的部分。

毫无疑问是树上打背包dp。

但具体设计还要注意一下。

一个问题是单点成链,这个要特判。

之后由于选择的都是链,所以每个点的度数不会超过2.

这样方程就出来了。

$ k \le n $ 的部分。

很明显不能背包了。

但“选正好k个求最大权值和”这个要求如果熟悉的话可能想到wqs二分。

打表试一下发现确实是上凸函数。

之后就按wqs二分的套路来,二分加权mid,求 $ dp_{x,k,deg} - mid * k $ 就完事了。

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
template<typename TP>inline void read(TP &tar)
{
	TP ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
	tar=ret*f;
}
namespace RKK
{
const int N=300011;
const int inf=0x3f3f3f3f;
const lint linf=0x3f3f3f3f3f3f3f;
struct sumireko{int to,ne;lint w;}e[N<<1];int he[N],ecnt;
void addline(int f,int t,lint w){e[++ecnt].to=t,e[ecnt].w=w;e[ecnt].ne=he[f],he[f]=ecnt;}
struct pat
{
	lint v,k;pat(lint v=-linf,lint k=inf):v(v),k(k){}
	bool operator<(const pat &p)const{return v==p.v?k>p.k:v<p.v;}
	pat friend operator+(const pat &pa,const pat &pb){return pat(pa.v+pb.v,pa.k+pb.k);}
}dp[N][3],dg[3],dtmp;

int n,kap;lint km;
void dfs(int x,int f)
{
	for(int i=he[x],t=e[i].to,w=e[i].w;i;i=e[i].ne,t=e[i].to,w=e[i].w)if(t!=f)
	{
		dfs(t,x);for(int p=0;p<3;p++) dg[p]=pat();
		for(int j=0;j<3;j++)for(int p=0;p<3;p++) dg[j]=max(dg[j],dp[x][j]+dp[t][p]);
		dg[1]=max(dg[1],dp[x][0]+max(dp[t][0]+pat(w-km,1),dp[t][1]+pat(w,0)));
		dg[2]=max(dg[2],dp[x][1]+max(dp[t][0]+pat(w,0),dp[t][1]+pat(w+km,-1)));
		memcpy(dp[x],dg,sizeof(dg));
	}
}
void dpclr(){for(int i=1;i<=n;i++) dp[i][0]=pat(0,0),dp[i][1]=pat(),dp[i][2]=pat(-km,1);}

int main()
{
	#ifdef RDEBUG
	freopen("sample.in","r",stdin);
	#endif
	read(n),read(kap),kap++;for(int i=2,x,y,w;i<=n;i++) read(x),read(y),read(w),addline(x,y,w),addline(y,x,w);
	lint ql=-1e8,qr=1e8,qm,qa;
	while(ql<=qr)
	{
		qm=ql+qr>>1,km=qm;
		dpclr(),dfs(1,0),dtmp=max(dp[1][0],max(dp[1][1],dp[1][2]));
		if(dtmp.k==kap){printf("%lld\n",dtmp.v+km*kap);return 0;}
		else if(dtmp.k>kap) ql=qm+1;
		else qr=qm-1,qa=qm;
	}
	km=qa;
	dpclr(),dfs(1,0),dtmp=max(dp[1][0],max(dp[1][1],dp[1][2]));
	printf("%lld\n",dtmp.v+km*kap);
	return 0;
}
}
int main(){return RKK::main();}

标签:二分,八省,ch,wqs,dtmp,qm,联考,dp
来源: https://www.cnblogs.com/rikurika/p/12838469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有