2020牛客暑期多校第九场 B Groundhog and Apple Tree

B Groundhog and Apple Tree
题意:
有一棵树,经过每条边会消耗一定体力,到达一个节点的时候可以恢复一定的体力,停下来休息时每一秒也可以恢复一点体力,
求至少需要恢复多少秒使得可以从节点1开始遍历到每个节点再回到节点1。
体力不能为负数,可以从0-正无穷,经过重复的节点时候不能再恢复体力,树上每条边最多只能遍历两次

做法:初步考虑下我们想要恢复的时间较少,且需要遍历每个子树,对于根节点来说,
访问一颗子树需要的总体力是一个定值,所以我们只需要考虑访问的顺序带来的影响。也就是遍历整棵树可以分成若干棵子树的遍历——考虑树形dp
定义状态:
Sta[i]表示i节点为根的子树的答案(需要的最少体力值)
Data[i]表示遍历i的子树后体力的变化,可能为负
则转移式:

然后就是Sta的转移:
假设所有的data和子树的sta求好了,对于当前节点则只需要考虑遍历子树的顺序:
1.data>=0,对于这种,我们应该先走sta较小的,这样可以保留最大的体力值,减少休息的时间
2.data<0,需要走sta+data较大的,这样可以保证休息时间更少

然后跑树形dp即可

点击查看代码块
#include 

#define ed end()
#define bg begin()
#define mkp make_pair
#define pb push_back
#define v(T) vector
#define all(x) x.bg,x.ed
#define newline puts("")
#define si(x) ((int)x.size())
#define rep(i,n) for(int i=1;i<=n;++i)
#define rrep(i,n) for(int i=0;i pii;
const int maxn = 1e5+10;
const int inf = 0x7f7f7f7f;
const ll inf_ll = 1ll*inf*inf;
const int Mod = 1e9+7;
const double eps = 1e-7;
struct node{
	int to;ll v;
	node(){}
	node(int _to,ll _v){
		to=_to;v=_v;
	}
	bool friend operator<(node a,node b){
		return a.v vec[maxn];
void dfs(int x,int fa)
{
	data[x]=val[x];sta[x]=0;
	vector > vp1,vp2;//vp1 part1,vp2 part2
	for(int i=0;i=0) vp1.push_back(make_pair(sta[s.to],s));
		else vp2.push_back(make_pair(sta[s.to]+data[s.to],s));
	}
	sort(vp1.begin(),vp1.end());
	sort(vp2.begin(),vp2.end());
	reverse(vp2.begin(),vp2.end());//倒序
	ll now=val[x];
	for(int i=0;i

你可能感兴趣的:(2020牛客暑期多校第九场 B Groundhog and Apple Tree)