[关闭]
@ysner 2018-04-21T11:09:49.000000Z 字数 1650 阅读 2139

Poj2054 color a tree&& [HNOI/AHOI2018]排列

贪心


题面

原题
某省选强化题
大致意思是给你一颗树,选父亲后才能选儿子。
每个点对答案的贡献为你在第几次选这个点 × 该点权值
问取完所有点最小答案是多少。

解析

贪心没学好,_ _ _ _ _(自己yy)

答案要求的其实是个选取序列。。。
我们可以发现,要保证答案最优性,最大点取的时间越小越好。
又可以发现,只要最大点父亲已选,下一个点选最大点肯定最优。
这时我们确定了一部分顺序,可以想,为什么不能把已确定的、前后相邻选的两点合并起来呢?
现在问题就是如何在几个大点中作抉择了。
可以发现,此时如果大点越大(是权值和,是时间和),就是性价比越高,先选越优。

对于

显然看起来有点鬼
我们要用更有区分度的比较方式
如果
那么
于是每次按着贪心策略合并点,对答案的贡献为其父亲选完所用时间×点权值,再把新点与被合并点的儿子相连即可。

  1. int main()
  2. {
  3. while(233)
  4. {
  5. memset(h,-1,sizeof(h));ans=0;cnt=0;
  6. n=gi();r=gi();
  7. if(!n&&!r) break;t[0]=1;
  8. fp(i,1,n) a[i]=gi(),t[i]=1;
  9. fp(i,1,n-1)
  10. {
  11. re int u=gi(),v=gi();
  12. add(u,v);f[v]=u;
  13. }
  14. f[r]=0;
  15. re int res=n;
  16. while(res--)
  17. {
  18. re int mx=1;
  19. fp(i,2,n)
  20. if(a[i]*t[mx]>a[mx]*t[i]) mx=i;
  21. ans+=a[mx]*t[f[mx]];
  22. a[f[mx]]+=a[mx];t[f[mx]]+=t[mx];
  23. for(re int i=h[mx];i+1;i=e[i].nxt)
  24. {
  25. re int v=e[i].to;
  26. f[v]=f[mx];
  27. add(f[mx],v);
  28. }
  29. a[mx]=-1;
  30. }
  31. printf("%lld\n",ans);
  32. }
  33. return 0;
  34. }

Update:发现一个很蛋疼的问题:用并查集就不用新建边了。

对于

裸贪心是的。
我们需要一个能马上提供最大点的堆来降低复杂度。

  1. struct node{int u,sz;ll w;bool operator < (const node &o) const {return w*o.sz>o.w*sz;}};
  2. priority_queue<node> Q;
  3. il void dfs(re int u)
  4. {
  5. vis[u]=1;++tim;
  6. for(re int i=h[u];i+1;i=e[i].nxt)
  7. {
  8. re int v=e[i].to;
  9. if(vis[v]) {puts("-1");exit(0);}
  10. dfs(v);
  11. }
  12. }
  13. il int find(re int x){return x==F[x]?x:F[x]=find(F[x]);}
  14. int main()
  15. {
  16. memset(h,-1,sizeof(h));ans=0;
  17. n=gi();
  18. fp(i,1,n) f[i]=gi(),add(f[i],i);
  19. dfs(0);if(tim<=n) return puts("-1"),0;
  20. fp(i,0,n) F[i]=i,sz[i]=1;
  21. fp(i,1,n) w[i]=gi(),Q.push((node){i,1,w[i]});
  22. re int u,p;
  23. while(!Q.empty())
  24. {
  25. node s=Q.top();Q.pop();u=find(s.u);
  26. if(sz[u]^s.sz) continue;//扔掉不符合当前情况的决策
  27. F[u]=p=find(f[u]);
  28. ans+=w[u]*sz[p];
  29. w[p]+=w[u];sz[p]+=sz[u];
  30. if(p) Q.push((node){p,sz[p],w[p]});
  31. }
  32. printf("%lld\n",ans);
  33. return 0;
  34. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注