BZOJ3829 : [Poi2014]FarmCraft
d[x]表示走完x的子树并回到x所需的时间
f[x]表示从走到x开始计时,x子树中最晚的点安装完的最早时间
d[x]=sum(d[i]+2),i是x的孩子
f[x]的计算比较复杂:
考虑将x的各棵子树按一定顺序排列,第i个走的子树是u,则它的贡献为sum(d[j]+2)+f[u]+1,j<i
即我们需要最小化max(sum(d[j]+2)+f[u]),设s[i]表示sum(d[j]+2),j<=i
对于序列中的两棵相邻子树i,j(i<j),交换它们只会影响它们两个的f[]
如果不交换比交换优
则有
max(s[i-1]+f[i],s[i-1]+d[i]+2+f[j])<max(s[i-1]+f[j],s[i-1]+d[j]+2+f[i])
max(f[i],d[i]+2+f[j])<max(f[j],d[j]+2+f[i])
以这个为cmp函数进行sort即可得到最优解序列,然后计算即可
f[x]=max(c[x],每个孩子的贡献)
ans=max(d[1]+c[1],f[1])
#include<cstdio> #include<algorithm> #define N 500010 int n,i,x,y,c[N],g[N],nxt[N<<1],v[N<<1],ed,d[N],f[N],a[N],t,sum; inline void read(int&a){char ch;while(!(((ch=getchar())>='0')&&(ch<='9')));a=ch-'0';while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';} inline int max(int a,int b){return a>b?a:b;} inline void up(int&a,int b){if(a<b)a=b;} inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} inline bool cmp(int x,int y){return max(f[x],d[x]+2+f[y])<max(f[y],d[y]+2+f[x]);} void dfs(int x,int fa){ int i; for(i=g[x];i;i=nxt[i])if(v[i]!=fa)dfs(v[i],x),d[x]+=d[v[i]]+2; for(t=sum=0,i=g[x];i;i=nxt[i])if(v[i]!=fa)a[++t]=v[i]; if(t)for(std::sort(a+1,a+t+1,cmp),i=1;i<=t;sum+=d[a[i++]]+2)up(f[x],sum+f[a[i]]+1); } int main(){ read(n); for(i=1;i<=n;i++)read(c[i]),f[i]=c[i]; for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x); dfs(1,0); return printf("%d",max(d[1]+c[1],f[1])),0; }