• 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 <bits/stdc++.h>
    
    #define ed end()
    #define bg begin()
    #define mkp make_pair
    #define pb push_back
    #define v(T) vector<T>
    #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<n;++i)
    #define srep(i,s,t) for(int i=s;i<=t;++i)
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> 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<b.v;
    	}
    };
    ll val[maxn],sta[maxn],data[maxn];
    vector<node> vec[maxn];
    void dfs(int x,int fa)
    {
    	data[x]=val[x];sta[x]=0;
    	vector<pair<ll,node> > vp1,vp2;//vp1 part1,vp2 part2
    	for(int i=0;i<vec[x].size();i++){
    		node s=vec[x][i];
    		if(s.to==fa) continue;
    		dfs(s.to,x);
    		data[s.to]-=s.v*2;
    		//由于当前这条边要走两遍,所以可以直接压到子儿子里时要*2
    		sta[s.to]+=s.v;
    		//这里由于只要考虑能不能走到子儿子就可以了,req是需要准备的Hp,所以不用*2
    		data[x]+=data[s.to];
    		if(data[s.to]>=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<vp1.size();i++){
    		node son=vp1[i].second;
    		if(now<sta[son.to]) sta[x]+=sta[son.to]-now,now=sta[son.to];
    		now+=data[son.to];//减去需要的Hp,然后加上遍历后能得到的Hp
    		if(now<0) sta[x]+=-now,now=0;//如果走着走着变成负了,要调成正的
    	}for(int i=0;i<vp2.size();i++){
    		node son=vp2[i].second;
    		if(now<sta[son.to]) sta[x]+=sta[son.to]-now,now=sta[son.to];
    		now+=data[son.to];
    		if(now<0) sta[x]+=-now,now=0;//同上
    	}
    }
    int main()
    {
    	int t,n,x,y;ll z;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d",&n);
    		for(int i=0;i<=n;i++) vec[i].clear();//记得清零!!!
    		for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
    		for(int i=1;i<n;i++){
    			scanf("%d%d%lld",&x,&y,&z);
    			vec[x].push_back(node(y,z));
    			vec[y].push_back(node(x,z));
    		}
    		dfs(1,-1);
    		printf("%lld
    ",sta[1]);
    	}
    }
    
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    SPOJ 4487. Can you answer these queries VI splay
    Oracle Enterprise Linux 64-bit 下Oracle11g的监听配置改动及測试步骤
    欧拉函数
    安装Windows7步骤
    在Eclipse中执行、配置Hadoop
    java设计模式演示样例
    VC中获取窗体句柄的各种方法
    HTML5 Canvas中实现绘制一个像素宽的细线
    Java实现 蓝桥杯VIP 基础练习 Sine之舞
    Java实现 蓝桥杯VIP 基础练习 Sine之舞
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13495466.html
Copyright © 2020-2023  润新知