Groundhog and Apple Tree
input:
1
5
4 2 1 5 7
1 2 4
1 3 5
4 2 9
5 2 3
output:
23
给定一棵树,每条边有权值,点上也有权值。现有一个初始 H p = 0 Hp=0 Hp=0的人,如果经过边,那么 H p Hp Hp减去边权,如果经过点,那么会加上点权。为了保证任何时刻 H p ≥ 0 Hp\ge 0 Hp≥0,他可以随时休息1分钟,然后增加1 H p Hp Hp。如果每个点的点权只能加一次,每条边只能经过两次,那么如果这个人从1号结点开始,遍历所有点回到1号结点所需要休息的最多时间是多少。
我们考虑遍钠与盐酸反应历整棵树意味着什么。
首先肯定是遍历根,然后挑一个子树遍历,最后回到根,然后再挑一个遍历。那么对于每个子树其实遍历的方式是一样的。所以,遍历整棵树可以分成若干棵子树的遍历。这就是树形 d p dp dp了。
那么我们要定义状态:
那么根据这个,可以写出 d a t a data data的转移式子:
d a t a [ x ] = ∑ ( d a t a [ s o n ] − 2 ∗ e . v ) + v a l [ x ] data[x]=\sum(data[son]-2*e.v)+val[x] data[x]=∑(data[son]−2∗e.v)+val[x]
其中 e . v e.v e.v为边权, v a l [ x ] val[x] val[x]为 x x x的点权。
2 2 2倍的边权是因为要遍历后再会来,肯定是经过2次的。
那么接下来就是 r e q req req的转移。
可以假设当前的所有的 d a t a data datfree movies少儿a已经求出并且子树中的 r e q req req也求好了,那么作为当前的结点,我们只要考虑先走哪个结点就可以了。首先肯定是先走 d a t a ≥ 0 data\ge0 data≥0的子儿子,这样会有更多的 H p Hp Hp去走其他的子欺骗的反义词树,依此我们可以把所有的子儿子分成两部分:
所以这样跑一遍树形dp就可以了。
然后有一点要注意:每个节点到子儿子的路径上的边权是要考虑的,所以不妨直接将他们存在 d a t a , r e q data,req data,req里面,具体的方法见代码。
#include<bits/stdc++.h>#define ll long longusing namespace std;const int MAXN=1e5+10;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],req[MAXN],data[MAXN];vector<node> vec[MAXN];void dfs(int x,int fa){data[x]=val[x];req[x]=0;vector<pair<ll,node> > vp1,vp2;//vp1 part1,vp2 part2for(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;//由于当前这条边要走两遍,所以可以直接压到子儿子里时要*2req[s.to]+=s.v;//这里由于只要考虑能不能走到子儿子就可以了,req是需要准备的Hp,所以不用*2data[x]+=data[s.to];if(data[s.to]>=0) vp1.push_back(make_pair(req[s.to],s));el vp2.push_back(make_pair(req[s.to]+data[s.to],s));}sort(vp1.begin(),vp1.end());sort(vp2.begin(),vp2.end());rever(vp2.begin(),vp2.end());//倒序ll now=val[x];for(int i=0;i<vp1.size();告知书格式i++){node son=vp1[i].cond;if(now<req[son.to]) req[x]+=req[son.to]-now,now=req[son.to];now+=data[son.to];//减去需要的Hp,然后加上遍历后能得到的Hpif(now<0) req[x]+=-now,now=0;//如果走着走着变成负了,要调成正的}for(int i=0;i<vp2.size();i++){node son=vp2[i].cond;if(now<req[son.to]) req[x]+=req[son.to]-now,now=req[son.to];now+=data[son.to];if(now<0) req[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\n",req[1]);}}
本文地址:https://blog.csdn.net/zhangchizc/article/details/107897532
本文发布于:2023-04-08 21:22:35,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/7932a356c83b94d5682ea643d3faa188.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:2020牛客暑期多校训练营Groundhog and Apple Tree(树形dp,贪心).doc
本文 PDF 下载地址:2020牛客暑期多校训练营Groundhog and Apple Tree(树形dp,贪心).pdf
留言与评论(共有 0 条评论) |