P3574 [POI2014]FAR-FarmCraft
题目链接
题意分析
做这道题的时候一定要明白 你所负责的是运输 安装是原住民的事情 是可以同时运输+多个安装
我们设置dp[x] 表示走完以x为根的子树 并且所有人都安装完之后的最大时间
设置time[x] 表示走完以x为根的子树所用的时间
那么当前的转移就是 其中y是x的儿子 sum表示走完y之前x的所有子树单纯运输所用的时间 +1表示从x到y
\[dp[x]=max(dp[x],dp[y]+sum+1) \]表示以y为根的子树中的点在走完之前的所有子树之后再安装
我们可以发现dp[x]的值和运输顺序有关 那么怎么确定运输顺序?
我们考虑一下 dp[x]是以x为根的子树都安装完的最大时间 而time[x]是以x为根的子树走完所用的时间
显然dp[x]≥time[x] 而dp[x]-time[x]表示运输完之后的闲置等待时间
我们希望先搞完闲置等待时间最多的 这样我们就可以在这些时间里做更多的事情 时间利用率更高
所以对于儿子 我们按照dp[x]-time[x]从大到小排序 然后转移
1.初始的时候dp[i]=ci(i≥2) 表示最大时间就是安装完所用的时间
2.为什么转移时是+1而不是+2
因为dp[x]-time[x]是等待时间 由于ci≥1 所以等待时间一定包含了从y返回x的时间
CODE:
#include
#define M 1008611
using namespace std;
int n,tot;
int num[M];
long long dp[M],tim[M];
int to[M],nex[M],head[M];
int tmp[M];
void add(int x,int y)
{to[++tot]=y;nex[tot]=head[x];head[x]=tot;}
bool cmp(const int &A,const int &B)
{return dp[A]-tim[A]>dp[B]-tim[B];}
void dfs(int now,int fat)
{
int cnt=0;
for(int i=head[now];i;i=nex[i])
{
int v=to[i];
if(v==fat) continue;
dfs(v,now);
tim[now]+=tim[v]+2;
}
for(int i=head[now];i;i=nex[i])
{
int v=to[i];
if(v==fat) continue;
tmp[++cnt]=v;
}
long long sum=0;
sort(tmp+1,tmp+cnt+1,cmp);
for(int i=1;i<=cnt;++i)
{
dp[now]=max(dp[now],sum+1+dp[tmp[i]]);
sum+=tim[tmp[i]]+2;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&num[i]);
for(int i=1,x,y;i