[BZOJ3829][Poi2014]FarmCraft 贪心

这个题应该是很容易想到贪心的,只要可是怎么贪才是科学的呢?
我们分析一下题干,对于每个边只能一进一出因此,对于树上的一棵子树,我们只要一进子树就必须遍历完,
因此我们只能进行一遍 dfs() 然后我们发现 dfs() 一遍的时间是一定的,
然后见每个妹子的时间就在这个时间轴上,
分析完了,我们说一下要贪什么。
我们先定义一个概念rest[]就是遍历完这个节点的子树以后我们还要为这个节点所费的时间
One_Stage :除了1节点,之外每个妹子一见面就杀du
Two_Stage :我们发现最后的答案是 Max(rest[1],c[1])+2*n-2
Three_Stage :然后我们考虑怎么找rest[1],
我们发现每个节点的最优rest[],是(子节点的rest[],减去其在这个子树里又经过的时间),再和(他的c[]减去遍历他的时间)取Max
这样我们线性一波就结局了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define MAXN 500005
using namespace std;
inline int read()
{
  register int sum=0;
  register char ch=getchar();
  while(ch<'0'||ch>'9')ch=getchar();
  while(ch>='0'&&ch<='9')
  {
    sum=(sum<<1)+(sum<<3)+ch-'0';
    ch=getchar();
  }
  return sum;
}
inline int Max(int x,int y)
{
  return x>y?x:y;
}
int a[MAXN],m[MAXN],n,t[MAXN];
vector<int> Via[MAXN];
void Dfs_T(int x,int fa)
{
  register int len=Via[x].size();
  for(register int i=0;i<len;++i)
  if(Via[x][i]!=fa)
  {
    Dfs_T(Via[x][i],x);
    t[x]+=2+t[Via[x][i]];
  }
}
inline void Init()
{
  n=read();
  for(register int i=1;i<=n;i++)a[i]=read();
  for(register int i=1,x,y;i<n;i++)x=read(),y=read(),Via[x].push_back(y),Via[y].push_back(x);
  Dfs_T(1,0);
}
int rest[MAXN];
int comp(const int x,const int y)
{
  return rest[x]>rest[y];
}
inline void Dfs_A(int x,int fa)
{
  register int len=Via[x].size();
  for(register int i=0;i<len;++i)
  if(Via[x][i]!=fa)Dfs_A(Via[x][i],x);
  sort(Via[x].begin(),Via[x].end(),comp);
  if(x!=1)rest[x]=a[x]-t[x];
  register int now=t[x];
  for(register int i=0;i<len;i++)
  if(Via[x][i]!=fa)
  {
    now-=2+t[Via[x][i]];
    rest[x]=Max(rest[x],rest[Via[x][i]]-now-1);
  }
  if(rest[x]<0)rest[x]=0;
}
inline void Work()
{
  Dfs_A(1,0);
  register int ans=Max(rest[1],a[1])+t[1];
  printf("%d",ans);
}
int main()
{
  Init();
  Work();
  return 0;
}
原文地址:https://www.cnblogs.com/TSHugh/p/7267655.html