[JZOJ5906]【NOIP2018模拟10.15】传送门

Description

给你一棵n个点的带边权无向树。
需要从1号点开始,将整棵树遍历一遍并最终回到1号点。
走到一个点时,可以在这个点设置一个传送门,只要地图上有两个传送门,就可以在它们之间以0的时间传送
如果要在当前节点设置传送门,并且已经有了两个传送门,那么需要选择之前的某一个传送门让他消失,也就是说任意时刻至多有两个传送门,且不能在同一节点。

求最小总时间。
n<=1000000

Solution

不妨以1为根。

首先我们可以肯定的是,最优走法一定是在祖先设置好了传送门,在某个后代遍历完了以后传回来。

如果没有传送门,时间显然是边权*2

有结论:如果当前节点有传送门,从它的某个子树中传了回来,再次走入这个子树一定不会更优。

换句话说,一个传送门的某个子树只有遍历完了才会传回来。
证明:
考虑我们为什么要重新走进去,那一定是我们传送回来的地方和我们还没遍历的地方在某个后代分叉了。

那么我们大可以直接将当前传送门设在分叉的位置,再暴力走回来,这样分叉到当前传送点路径都是两遍,而分叉以下的部分都是1遍。

这样我们就可以DP了
G [ i ] G[i] G[i]为遍历完i为根的子树,不用传送门的时间(就是边权*2)
F [ i ] F[i] F[i]为可以用传送门的最优时间

考虑怎么转移F
假设我们当前节点为i,DP完的儿子是p
要么在当前节点设传送门,暴力走p,再传回来,很明显我们会从最深的那个叶子传回来。
要么在p的子树中设传送门,暴力走这条边2次(下去1次,回来1次)
因此 F [ i ] = ∑ p ∈ s o n [ i ] m i n ( G [ p ] + l e n g t h [ i ] [ p ] − d e e p e s t [ p ] , 2 ∗ l e n g t h [ i ] [ p ] + F [ p ] ) F[i]=\sum\limits_{p\in son[i]}min(G[p]+length[i][p]-deepest[p],2*length[i][p]+F[p]) F[i]=pson[i]min(G[p]+length[i][p]deepest[p],2length[i][p]+F[p])
deepest[i]表示i子树中到i最远的叶子。

最后答案就是F[1]

Code

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 1000005
#define LL long long
using namespace std;
int pr[2*N],dt[2*N],fs[N],n,m,nt[2*N];
LL f[N],g[N],des[N];
void link(int x,int y,int z)
{
	nt[++m]=fs[x];
	dt[fs[x]=m]=y;
	pr[m]=z;
}
void dfs(int k,int fa)
{
	f[k]=g[k]=0;
	LL v=0;
	for(int i=fs[k];i;i=nt[i])
	{
		int p=dt[i];
		if(p!=fa)
		{
			dfs(p,k);
			g[k]=g[k]+2*pr[i]+g[p];
			f[k]=f[k]+min(2*pr[i]+f[p],g[p]+pr[i]-des[p]);
			des[k]=max(des[k],des[p]+pr[i]);
		}
	}
	//f[k]=min(f[k],g[k]-des[k]);
}
int main()
{
	cin>>n;
	fo(i,1,n-1)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		link(x,y,z),link(y,x,z);
	}
	dfs(1,0);
	printf("%lld\n",f[1]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值