【动态规划】连珠线

198 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情

[APIO2014] 连珠线

题目描述

在达芬奇时代,有一个流行的儿童游戏称为连珠线。当然,这个游戏是关于珠子和线的。线是红色或蓝色的,珠子被编号为 11nn。这个游戏从一个珠子开始,每次会用如下方式添加一个新的珠子:

Append(w, v):一个新的珠子 ww 和一个已经添加的珠子 vv 用红线连接起来。

Insert(w, u, v):一个新的珠子 ww 插入到用红线连起来的两个珠子 u,vu, v 之间。具体过程是删去 u,vu, v 之间红线,分别用蓝线连接 u,wu, ww,vw, v

每条线都有一个长度。游戏结束后,你的最终得分为蓝线长度之和。

给你连珠线游戏结束后的游戏局面,只告诉了你珠子和链的连接方式以及每条线的长度,没有告诉你每条线分别是什么颜色。

你需要写一个程序来找出最大可能得分。即,在所有以给出的最终局面结束的连珠线游戏中找出那个得分最大的,然后输出最大可能得分。

输入格式

第一行一个正整数 nn,表示珠子的数量。珠子从 11nn 编号。

接下来 n1n - 1 行每行三个整数 ai,bi,cia_i, b_i, c_i。保证 1ai<bin1 \leq a_i < b_i \leq n1ci100001 \leq c_i \leq 10000。表示 aia_i 号珠子和 bib_i 号珠子间连了长度为 cic_i 的线。

输出格式

输出一个整数,表示最大可能得分。

样例 #1

样例输入 #1

5
1 2 10
1 3 40
1 4 15
1 5 20

样例输出 #1

60

样例 #2

样例输入 #2

10
4 10 2
1 2 21
1 3 13
6 7 1
7 9 5
2 4 3
2 5 8
1 6 55
6 8 34

样例输出 #2

140

提示

【样例描述1】

可以通过如下方式获得 6060 分:首先从 33 号珠子开始。

5533 连起来。(线长度任意)

3355 之间插入 11。(线长分别为 40402020)。

2211 用长度为 1010 的线连起来。

4411 用长度为 1515 的线连起来。

【限制与约定】

第一个子任务共 13 分,满足 1n101 \leq n \leq 10

第二个子任务共 15 分,满足 1n2001 \leq n \leq 200

第三个子任务共 29 分,满足 1n100001 \leq n \leq 10000

第四个子任务共 43 分,满足 1n2000001 \leq n \leq 200000

#include<cstdio>
#include<climits>
typedef long long ll;
int cnt=0;
ll mx1[200005],mx2[200005],vg[200005];
ll f[200005][2],g[200005][2],k[200005][2];
int son1[200005],son2[200005];
int h[200005],to[400005],ver[400005],w[400005];
inline int read() {
	register int x=0,f=1;register char s=getchar();
	while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
	while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
	return x*f;
}
inline void add(int x,int y,int z) {
	to[++cnt]=y;
	ver[cnt]=h[x];
	w[cnt]=z;
	h[x]=cnt;
}
inline void swap(int &x,int &y) {int tmp=x;x=y;y=tmp;}
inline void swap(ll &x,ll &y) {ll tmp=x;x=y;y=tmp;}
inline ll max(const ll &x,const ll &y) {return x>y? x:y;}
inline void dfs1(int x,int fa) {
	mx1[x]=mx2[x]=INT_MIN; son1[x]=son2[x]=0;
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i];
		if(y==fa) continue;
		vg[y]=w[i];dfs1(y,x);
		f[x][0]+=max(f[y][0],f[y][1]+w[i]);
		ll val=f[y][0]+w[i]-max(f[y][0],f[y][1]+w[i]);
		if(mx1[x]<val) {son2[x]=son1[x];mx2[x]=mx1[x];son1[x]=y;mx1[x]=val;}
		else if(mx2[x]<val) {son2[x]=y;mx2[x]=val;}	
	}
	f[x][1]=f[x][0]+mx1[x];
}
inline void dfs2(int x,int fa) {
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i];
		if(y==fa) continue;
		if(son1[x]==y) {swap(mx1[x],mx2[x]);swap(son1[x],son2[x]);}
		k[x][0]=g[x][0]-max(f[y][0],f[y][1]+w[i]);k[x][1]=k[x][0]+mx1[x];
		if(fa!=-1) {k[x][1]=max(k[x][1],k[x][0]+k[fa][0]+vg[x]-max(k[fa][0],k[fa][1]+vg[x]));}
		g[y][0]=f[y][0]+max(k[x][0],k[x][1]+w[i]);
		if(mx1[x]<mx2[x]) {swap(mx1[x],mx2[x]);swap(son1[x],son2[x]);}
		dfs2(y,x);
	}
}
int main() {
	int n=read(); ll ans=0;
	for(register int i=1;i<n;++i) {int x=read(),y=read(),z=read(); add(x,y,z);add(y,x,z);}
	dfs1(1,-1); g[1][0]=f[1][0]; dfs2(1,-1);
	for(register int i=1;i<=n;++i) ans=max(ans,g[i][0]);
	printf("%lld",ans);
	return 0;
}