题目描述
在一个叫做比特村的小村庄中,有n−1n-1n−1条路连接着这个村庄中的全部nnn个房子。
每两个房子之间都有一条唯一的通路。
这些房子的编号为1至nnn。
1号房子属于村庄的管理员比特安萨尔。
为了提升村庄的科技使用水平,nnn台电脑被快递到了比特安萨尔的房子。
每个房子都应该有一台电脑,且分发电脑的任务就落在了比特安萨尔的肩上。
比特村的居民一致同意去玩农场物语这个游戏的最新快照版,而且好消息是他们很快就要得到他们最新的高配置电脑了。
比特安萨尔将所有电脑都装在了他的卡车上,而且他准备好完成这个艰巨的任务了。
他的汽油恰好够走每条路两遍。
在每个房子边,比特安萨尔把电脑贴心的配送给居民,且立即前往下一个房子。(配送过程不花费任何时间)
只要每间房子的居民拿到了他们的新电脑,它们就会立即开始安装农场物语。
安装农场物语所用的时间根据居民的科技素养而定。幸运的是,每间房子中居民的科技素养都是已知的。
在比特安萨尔配送完所有电脑后,他会回到他自己的1号房子去安装他自己的农场物语。
用卡车开过每条路的时间恰好是1分钟,而居民开电脑箱的时间可以忽略不计。(因为他们太想玩农场物语了)
请你帮助比特安萨尔算出从开始配送到所有居民都玩上了农场物语的最少时间。
输入输出格式
输入格式:
第一行包含一个整数n(2≤n≤500000)n(2 leq n leq 500000)n(2≤n≤500000),代表比特村中有多少房子。
第二行包含nnn个整数c1,c2,⋯,cn(1≤ci≤109)c_1, c_2, ⋯, c_n(1 leq c_i leq 10^9)c1,c2,⋯,cn(1≤ci≤109),每个数都被单个空格隔开。cic_ici是第i号房间中居民安装农场物语所用的时间。
接下来的n−1n-1n−1行代表了每一条路的两个顶点。两个顶点aaa和bbb满足(1≤a<b≤n)(1 leq a < b leq n)(1≤a<b≤n),两个数之间有一个空格。
输出格式:
一行,包含一个整数,代表题目中所说的最小时间。
感谢@deadpool123 提供的翻译
树形dp,sum[i]表示走完以i为根的子树并回到i的时间
f[i]表示第i颗子树的最优解
根据贪心排序
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn = 5e5+10; int n,size,head[maxn],sum[maxn],cost[maxn]; int id[maxn]; ll f[maxn]; struct edge { int v,nex; }e[maxn<<1]; void adde(int u,int v) { e[size].v=v;e[size].nex=head[u];head[u]=size++; } bool cmp(int a,int b) { return sum[a]+f[b]<sum[b]+f[a]; } void dfs(int u,int fa) { if(u!=1) f[u]=cost[u]; for(int i=head[u];~i;i=e[i].nex) { int v=e[i].v; if(v==fa) continue; dfs(v,u); } int ct=0; for(int i=head[u];~i;i=e[i].nex) { int v=e[i].v; if(v==fa) continue; id[++ct]=v; } sort(id+1,id+1+ct,cmp); for(int i=1;i<=ct;i++) { f[u]=max(f[u],(ll)sum[u]+1+f[id[i]]); sum[u]+=sum[id[i]]+2; } } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",cost+i); for(int i=1;i<n;i++) { int u,v;scanf("%d%d",&u,&v); adde(u,v);adde(v,u); } dfs(1,-1); printf("%lld",max(f[1],(ll)2*n-2+cost[1])); return 0; }