1. 程式人生 > >[POI2014]FAR-FarmCraft

[POI2014]FAR-FarmCraft

傳送門

preface

  下午頹的時候看到這道題,當時也沒怎麼想,就去找題解,結果聽不懂ta在講啥。晚上自己回來弄一弄就完了,就寫個題解翻譯一下。

分析

  這個樹形dp就沒什麼好說的了。用dp[i]表示把以i為根的子樹全處理完後最少還要多少時間(劃重點)。剛開始想最常規的思路,提交一發只對了一個點,然後才改用題解的dp。這樣的話,最後只用判斷c1和dp[1]哪個大再加上所有邊的兩倍就可以了。

  考慮轉移。貪心的想,我們每到一個節點就開始安裝,然後走這個節點的兒子裡dp值最大的那個,顯然,這樣走可以保證不比其他方式劣。所以把i的兒子用一個vector全部記錄下來,按照dp值從大到小排序。因為dp[i]受i的兒子中最大dp值限制,所以dp[i]就是每個兒子的dp值減去按照貪心策略遍歷每個兒子的時間的最大值。再把處理後的dp[i]和ci

-(sizi-1)*2取max就可以了。

  p.s.這題也有省選難度?

code

#include<bits/stdc++.h>
#define ll long long
#define maxn 500010
#define reg register
using namespace std;
int n,w[maxn],head[maxn],k,dp[maxn],dep[maxn],siz[maxn];
struct node
{
    int to,nxt;
} edge[maxn*2];
void add(int u,int v)
{
    edge[++k].nxt=head[u];
    edge[k].to
=v; head[u]=k; } bool cmp(int x,int y) { return dp[x]>dp[y]; } void dfs(int u,int fa) { siz[u]=1; vector<int> tmp; for(int i=head[u]; i; i=edge[i].nxt) { int v=edge[i].to; if(v!=fa) { tmp.push_back(v); dep[v]=dep[u]+1; dfs(v,u); siz[u]
+=siz[v]; } } if(u!=1) dp[u]=w[u]-(siz[u]-1)*2; int sum=(siz[u]-1)*2; sort(tmp.begin(),tmp.end(),cmp); for(int i=0,sz=tmp.size(); i<sz; i++) { sum-=siz[tmp[i]]*2; dp[u]=max(dp[u],dp[tmp[i]]-sum-1); } dp[u]=max(dp[u],0); } int main() { scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&w[i]); int x,y; for(int i=1; i<n; i++) { scanf("%d%d",&x,&y); add(x,y),add(y,x); } dfs(1,1); printf("%d\n",max(dp[1],w[1])+(n-1)*2); return 0; }