【题意】给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小。n<=50000,h<=100。

【算法】树的重心

【题解】代码参考自:cgh_Andy

观察要求容易发现和重心的定义【所有点距离和最小】十分相似。

要把树分成两部分,于是考虑枚举割掉一条边后,在两棵树中各自找重心。

这样做得到的方案虽然不一定满足题意,但最优解一定在方案中,且不满足题意的方案一定不会比最优解小。

用树形DP求重心,总复杂度O(n^2)。

观察到最大深度<=100,可以用【往子树权和>sum/2的子树走】的方法求解。

这种做法的正确性:设当前点为重心的答案是ans,则往子树走ans=ans-sum[son]+(sum-sum[son])=ans+sum-2*sum[son],由此可知当sum[son]>sum/2时对答案有贡献。

理解做法后,关键在如何简洁的实现。

对每个点计算size,mx(最大儿子),mx2(次大儿子)。mx只记编号

计算初始重心答案:s+=size[x],x=2~n。(这里技巧性很强,将所有size都加一次,最底端自然累计了路径数)

枚举边u-v,将边上端v到根的size修改,sum=s后修改sum(这里用sum减去路径数次的size[u],这样就是初始双中心设在1和u了)。

然后从初始双重心往下找重心即可,记得一部分sum是sum[1],另一部分sum是sum[u]。

整个过程的答案只需要:ans+=sum-2*sum[son]。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define ll long long
  5. using namespace std;
  6. const int maxn=;
  7. const ll inf=1ll<<;
  8. int fa[maxn],deep[maxn],tot,first[maxn],mx[maxn],mx2[maxn],n,w[maxn];
  9. ll ans,size[maxn];
  10. struct edge{int u,v,from;}e[maxn*];
  11.  
  12. void insert(int u,int v){tot++;e[tot].u=u;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
  13. void dfs(int x,int f){
  14. size[x]=w[x];mx[x]=mx2[x]=;
  15. for(int i=first[x];i;i=e[i].from)if(e[i].v!=f){
  16. deep[e[i].v]=deep[x]+;
  17. fa[e[i].v]=x;
  18. dfs(e[i].v,x);
  19. size[x]+=size[e[i].v];
  20. if(size[e[i].v]>size[mx[x]]){mx2[x]=mx[x];mx[x]=e[i].v;}
  21. else if(size[e[i].v]>size[mx2[x]])mx2[x]=e[i].v;
  22. }
  23. }
  24. int main(){
  25. scanf("%d",&n);
  26. int u,v;
  27. memset(first,,sizeof(first));
  28. tot=;
  29. for(int i=;i<n;i++){
  30. scanf("%d%d",&u,&v);
  31. insert(u,v);insert(v,u);
  32. }
  33. for(int i=;i<=n;i++)scanf("%d",&w[i]);
  34. dfs(,);
  35. ll s=;ans=inf;
  36. for(int i=;i<=n;i++)s+=size[i];
  37. for(int k=;k<=tot;k+=){
  38. int u=e[k].u,v=e[k].v;
  39. if(deep[u]<deep[v])swap(u,v);
  40. ll sum=s;
  41. for(int x=v;x;x=fa[x])size[x]-=size[u],sum-=size[u];
  42. int x=,y;
  43. while(){
  44. if(size[mx[x]]>size[mx2[x]]&&mx[x]!=u)y=mx[x];else y=mx2[x];
  45. if(size[y]*>size[])sum+=size[]-*size[y],x=y;else break;
  46. }
  47. x=u;
  48. while(){
  49. if(size[mx[x]]*>size[u])sum+=size[u]-*size[mx[x]],x=mx[x];else break;
  50. }
  51. ans=min(ans,sum);
  52. for(int x=v;x;x=fa[x])size[x]+=size[u];
  53. }
  54. printf("%lld",ans);
  55. return ;
  56. }

【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站的更多相关文章

  1. BZOJ3302: [Shoi2005]树的双中心

    BZOJ3302: [Shoi2005]树的双中心 https://lydsy.com/JudgeOnline/problem.php?id=3302 分析: 朴素算法 : 枚举边,然后在两个连通块内 ...

  2. 【BZOJ3302】[Shoi2005]树的双中心 DFS

    [BZOJ3302][Shoi2005]树的双中心 Description Input 第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号.接下来N-1行,每行两个整 ...

  3. 题解-SHOI2005 树的双中心

    SHOI2005 树的双中心 给树 \(T=(V,E)(|V|=n)\),树高为 \(h\),\(w_u(u\in V)\).求 \(x\in V,y\in V:\left(\sum_{u\in V} ...

  4. luogu P2726 [SHOI2005]树的双中心

    传送门 强行安利->巨佬题解 如果只有一个点贡献答案,那么答案显然是这棵树的带权重心,这个是可以\(O(n)\)求的.一个\(O(n^2)\)暴力是枚举两个集合之间的分界边,然后对这两个集合分别 ...

  5. 【洛谷 P2726】 [SHOI2005]树的双中心(树的重心)

    先考虑一个\(O(N^2)\)做法. 设选的两个点为\(x,y\),则一定可以将树分成两个集合\(A,B\),使得\(A\)集合所有点都去\(x\),\(B\)集合所有点都去\(y\),而这两个集合的 ...

  6. [SHOI2005]树的双中心

    题目链接:Click here Solution: 首先我们要知道,选择两个点\(A,B\),必定存在一条边,割掉这条边,两个集合分别归\(A,B\)管 再结合题目,我们就得到了一个暴力的\(n^2\ ...

  7. bzoj 3302&2447&2103 树的双中心 树形DP

    题目: 题解: bzoj 3302 == 2447 == 2103 三倍经验 首先我们考虑枚举两个中心的位置,然后统计答案. 我们发现,一定有一部分点离第一个中心更近,另一部分点离第二个中心更近 如果 ...

  8. BZOJ 2103/3302/2447 消防站 树的重心【DFS】【TreeDP】

    2103: Fire 消防站 Time Limit: 30 Sec  Memory Limit: 259 MBSubmit: 157  Solved: 116[Submit][Status][Disc ...

  9. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

随机推荐

  1. WPF和Expression Blend开发实例:充分利用Blend实现一个探照灯的效果

    本篇文章阅读的基础是在读者对于WPF有一定的了解并且有WPF相关的编码经验,对于Blend的界面布局有基础的知识.文章中对于相应的在Blend中的操作进行演示,并不会进行细致到每个属性的介绍.同时,本 ...

  2. keepalived 高可用(IP飘移)

    什么是keepalived? keepalived是一个在c中编写的路由软件,该项目的主要目标是为Linux系统和基于Linux的基础架构提供简单和强大的设备,用于loadbalance和高可用性.l ...

  3. Java设计模式 - 单例模式 (懒汉方式和饿汉方式)

    概念: Java中单例模式是一种常见的设计模式,单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的写法有好几种,这 ...

  4. HDU4669_Mutiples on a circle

    题目的意思是给你一些数字a[i](首位相连),现在要你选出一些连续的数字连续的每一位单独地作为一个数位.现在问你有多少种选择的方式使得选出的数字为k的一个倍数. 其实题目是很简单的.由于k不大(200 ...

  5. HBASE+Solr实现详单查询--转

    原文地址:https://mp.weixin.qq.com/s?srcid=0831kfMZgtx1sQbzulgeIETs&scene=23&mid=2663994161&s ...

  6. BZOJ 1237 配对(DP)

    给出两个长度为n的序列.这两个序列的数字可以连边当且仅当它们不同,权值为它们的绝对值,求出这个二分图的最小权值完全匹配.没有输出-1. n<=1e5.用KM会TLE+MLE. 如果连边没有限制的 ...

  7. 获取网站图标Icon

    通常情况下,做网站的都会给自己的网站添加一个Icon,浏览器上一长排的标签页,用Icon来区分就显得更加醒目.现在想找一个没有Icon的网站并不好找,可见没有Icon的网站是多么的业余啊." ...

  8. [六]SpringBoot 之 连接数据库(mybatis)

    在进行配置之前首先要了解springboot是如何使用纯java代码方式初始化一个bean的 以前的版本是在xml中使用beans标签,在其里面配置bean,那么纯Java代码怎么实现呢? 答案就是使 ...

  9. Fdisk 分区详解

    Fdisk 分区详解 来源 http://blog.itpub.net/20674423/viewspace-722812/ 1.             通过Fdisk查看系统分区详细信息: Fdi ...

  10. EVE-NG FAQ

    EVE-NG FAQ How to install EVE on bare box using Ubuntuoriginal ISO distro. Get Ubuntu ISO: https://w ...