欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Poi2014]FarmCraft

程序员文章站 2022-07-13 12:00:47
...

首先,每条边只能被走两次,就是一遍dfs,

求f[x],f[x]代表以x为节点的子树遍历完需要的步数

显然,对于叶子节点,f[x]=0;

我们维护一个rest[x],代表假设x为根节点,遍历完子树后,还需要多长时间完成所有安装

显然ans=max(rest[1],c[1]);每个节点的rest由子节点更新

对于节点x,把它子节点的rest排序,先走大的肯定是最优的,rest[x]=max{max{rest[son[x]]-ti},c[x]-f[x]}

ti代表遍历完这个子节点后走其他子节点还需要走的步数,对于叶节点,rest[x]=c[x];

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define N  500005
using namespace std;
int n,m;
int c[N],f[N],fa[N];
bool vis[N];
struct edge
{ 
    int to,ne;  
}b[N*2];
struct node
{
    int f,rest;  
};
int k=0,head[N];
void add(int x,int y)
{
     b[k].to=y;b[k].ne=head[x];head[x]=k++;
}
void dfs(int now,int father)
{
     fa[now]=father;
     f[now]=0;
     for(int i=head[now];i!=-1;i=b[i].ne)
     if(b[i].to!=father){
        dfs(b[i].to,now);
        f[now]+=f[b[i].to]+2;
     }
}
int comp_(const node &w,const node &e)
{
     return w.rest>e.rest;
}
int dp(int x)
{
    if(f[x]==0) return c[x];
    vector<node> g;
    node tmp;
    int js=0,sum=f[x];
    for(int i=head[x];i!=-1;i=b[i].ne)
    if(b[i].to!=fa[x]){
       tmp.rest=dp(b[i].to);
       tmp.f=f[b[i].to];
       g.push_back(tmp);
    }
    int ans=0,ti=0;
    sort(g.begin(),g.end(),comp_);
    for(int i=0;i<g.size();i++)
    {
      int t=sum-ti-g[i].f-1;
      ans=max(max(0,g[i].rest-t),ans);
      ti+=(g[i].f+2);
    }
    if(x==1) ans=max(ans,c[1]);
    else  ans=max(ans,max(c[x]-f[x],0));
    return ans;
}
int main()
{
    int x,y;
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
       scanf("%d",&c[i]);
    }
    for(int i=1;i<n;i++){
       scanf("%d%d",&x,&y);
       add(x,y); add(y,x);
    }
    dfs(1,0);
    int ans=dp(1)+2*(n-1);
    printf("%d\n",ans);
    while(1);
    return 0;
}