翻譯其實已經很明確了ios
這題一眼就是貪心啊,但貪心的方法要思索一下,首先是考慮先走時間多的子樹,但不太現實,由於時間跟點的個數也有關係,並且頗有可能另一棵子樹不去走會閒置很長時間,就是這棵子樹原本能夠走一遍而後在子樹裝軟件的時候去走別的樹,因此不能這麼貪心。那,要怎麼辦呢?
對於一棵子樹,咱們必需要走的是跑路時間,而安裝能夠在去別的子樹走的時候幹,因此咱們確定要先弄安裝時間-跑路時間最大的子樹,由於這樣的話,咱們就能夠在它安裝的時候去弄別的子樹,證實用反證法,先弄別的子樹最後時長必定大於先弄它,因此跑完每個子樹後,把它的安裝時間和跑路時間扔到堆裏,最後把堆取完,就完了,狀態轉移方程\(DP[u]=max(DP[son]+g[u]+1)\),g數組記錄的跑路時間。數組
首先呢,longlong不須要,爆不掉。
而後是加邊,加單向邊會出問題,加完從一號點開始可能不能走遍整張圖,因此只能加雙向邊,加雙向邊數組要開2倍啊啊啊啊啊,本蒟蒻忘開而後RE了,接着我把5e5改爲了6e5,還RE,而後我覺得遞歸炸了,調了半天,我是否是傻。。。。spa
#include<iostream> #include<algorithm> using namespace std; const int N=6e5+10; struct Edge{ int nxt,to; }e[N<<1]; int Head[N],len; void Ins(int a,int b){ e[++len].to=b;e[len].nxt=Head[a];Head[a]=len; } struct Node{ int f,siz; Node(){} Node(int a,int b){f=a,siz=b;} bool operator < (const Node&A)const{ return f-siz<A.f-A.siz; } }; int dp[N],g[N],val[N],que[N]; void dfs(int u,int fa){ priority_queue<Node> q; if(u-1)dp[u]=val[u]; for(int i=Head[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; dfs(v,u);q.push(Node(dp[v],g[v])); } while(!q.empty()){ Node now=q.top();q.pop(); dp[u]=max(dp[u],now.f+g[u]+1); g[u]+=now.siz+2; } } int main(){ ios::sync_with_stdio(false); int n; cin>>n; for(int i=1;i<=n;i++) cin>>val[i]; for(int i=1;i<n;i++){ int a,b; cin>>a>>b; Ins(a,b);Ins(b,a); } dfs(1,0); cout<<max(dp[1],val[1]+g[1]); return 0; }