先考虑一个\(O(N^2)\)做法。

设选的两个点为\(x,y\),则一定可以将树分成两个集合\(A,B\),使得\(A\)集合所有点都去\(x\),\(B\)集合所有点都去\(y\),而这两个集合的分界点就是树上的一条边。于是考虑枚举断哪条边,然后对两边分别跑一遍带权树的重心,统计答案加起来取最小值就行了。

现在进行优化,求树的重心的方法可以参考医院设置

以\(1\)为根建树,\(f[u]\)表示所有点到\(u\)的总距离。(人数乘以距离)

转移方程是:

\[f[v]=f[u]+size[1]-size[v]-size[v]
\]

可以发现,只有当\(size[v]*2>size[1]\)时\(v\)比\(u\)更优,而且满足\(size[v]*2>size[1]\)的\(v\)数量\(<=1\)。

所以我们可以预处理出每个点的子树大小最大的儿子和次大的儿子,每次断边时自下而上修改其所有祖先的\(size\)大小,这时最大儿子可能变小,进而被次大儿子替代,直接判断一下然后走此时的大儿子就行。易得时间复杂度为\(O(NH)\),这也就是题中提到树的高度不超过\(100\)的原因吧。

  1. #include <cstdio>
  2. #include <algorithm>
  3. #define INF 2147483647
  4. using namespace std;
  5. #define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
  6. #define Close fclose(stdin);fclose(stdout);
  7. int s, w; char ch;
  8. inline int read(){
  9. s = 0; ch = getchar();
  10. while(ch < '0' || ch > '9') ch = getchar();
  11. while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar();}
  12. return s;
  13. }
  14. const int MAXN = 100010;
  15. struct Edge{
  16. int next, to;
  17. }e[MAXN << 1];
  18. int head[MAXN], num, a[MAXN], size[MAXN], f[MAXN], val[MAXN], dep[MAXN], son[MAXN], Sson[MAXN], A, B, n, root, ans = INF, cut;
  19. inline void Add(int from, int to){
  20. e[++num].to = to; e[num].next = head[from]; head[from] = num;
  21. e[++num].to = from; e[num].next = head[to]; head[to] = num;
  22. }
  23. int getsize(int u, int fa){
  24. size[u] = a[u]; f[u] = fa; dep[u] = dep[fa] + 1;
  25. for(int i = head[u]; i; i = e[i].next)
  26. if(e[i].to != fa){
  27. getsize(e[i].to, u);
  28. size[u] += size[e[i].to];
  29. val[u] += val[e[i].to] + size[e[i].to];
  30. if(size[e[i].to] > size[son[u]]){
  31. Sson[u] = son[u];
  32. son[u] = e[i].to;
  33. }
  34. else if(size[e[i].to] > size[Sson[u]])
  35. Sson[u] = e[i].to;
  36. }
  37. }
  38. void getans(int u, int now, int all, int &res){
  39. res = min(res, now);
  40. int v = son[u];
  41. if(v == cut || size[Sson[u]] > size[son[u]]) v = Sson[u]; //如果size变化后次大大于最大
  42. if(!v) return;
  43. if(size[v] * 2 > all) getans(v, now + all - size[v] - size[v], all, res); //如果size[v]*2<=all就没有继续往下走的意义了,因为此时u一定最优
  44. }
  45. int solve(int u){
  46. for(int i = head[u]; i; i = e[i].next)
  47. if(e[i].to != f[u]){
  48. cut = e[i].to; //断边
  49. A = B = INF;
  50. for(int now = u; now; now = f[now]) size[now] -= size[e[i].to]; //自下而上修改其父亲size
  51. getans(1, val[1] - val[e[i].to] - dep[e[i].to] * size[e[i].to], size[1], A);
  52. getans(e[i].to, val[e[i].to], size[e[i].to], B); //求两个集合的答案
  53. ans = min(ans, A + B);
  54. for(int now = u; now; now = f[now]) size[now] += size[e[i].to]; //回溯
  55. solve(e[i].to);
  56. }
  57. }
  58. int main(){
  59. //Open("practice");
  60. n = read(); dep[0] = -1;
  61. for(int i = 1; i < n; ++i) Add(read(), read());
  62. for(int i = 1; i <= n; ++i) a[i] = read();
  63. getsize(1, 0);
  64. solve(1);
  65. printf("%d\n", ans);
  66. return 0;
  67. }

【洛谷 P2726】 [SHOI2005]树的双中心(树的重心)的更多相关文章

  1. 题解-SHOI2005 树的双中心

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

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

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

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

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

  4. 洛谷 P3377 【模板】左偏树(可并堆)

    洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...

  5. 洛谷P3377 【模板】左偏树(可并堆) 题解

    作者:zifeiy 标签:左偏树 这篇随笔需要你在之前掌握 堆 和 二叉树 的相关知识点. 堆支持在 \(O(\log n)\) 的时间内进行插入元素.查询最值和删除最值的操作.在这里,如果最值是最小 ...

  6. 【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站

    [题意]给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小.n<=50000,h<=100. [算法]树的重心 [题解]代码参考自:cgh_Andy 观察 ...

  7. 洛谷P3434 [POI2006]KRA-The Disks(线段树)

    洛谷题目传送门 \(O(n)\)的正解算法对我这个小蒟蒻真的还有点思维难度.洛谷题解里都讲得很好. 考试的时候一看到300000就直接去想各种带log的做法了,反正不怕T...... 我永远只会有最直 ...

  8. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  9. 洛谷AT2046 Namori(思维,基环树,树形DP)

    洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...

  10. ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】

    题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...

随机推荐

  1. Backbone.js源码浅介

    终于看到一个只有一千多行的js框架了,于是抱着一定可以看懂他的逻辑的心态,查看了他的整个源码,进去之后才发现看明白怎么用容易,看懂怎么写的就难了,于是乎有了这篇博客的标题:浅介,只能粗浅的介绍下Bac ...

  2. 20135202闫佳歆--week5 课本18章学习笔记

    第十八章 调试 内核级开发的调试工作远比用户级开发艰难的多. 一.准备开始 准备工作需要的是: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 在这一章里,调试的主要思想是让bug重现 ...

  3. 《Linux内核分析》第三周:Linux系统启动过程

    杨舒雯 原创作品转载请注明出处 Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验--使用gdb跟踪调试内 ...

  4. 回忆--RYU流量监控

    RYU流量监控 前言 Ryu book上的一个流量监控的应用,相对比较好看懂 实验代码 github源码 from ryu.app import simple_switch_13 from ryu.c ...

  5. Manjaro Linux 没有声音

    在Multimedia中的PulseAudio Volume Control中的设置可以解决

  6. 团队作业(五)-笔记app top5

    在互联网快速发展的情况下,各个行业的软件层出不穷,五花八门.各个行业都有相当多的软件介入其中,在如此多的软件之中,便有了相当激烈的竞争角逐.今天我们十五万的总冠军就着笔记APP行业中位列top 5的软 ...

  7. PHP 验证IP的合法性

    php验证IP的合法性! function get_ip(){ //判断服务器是否允许$_SERVER if(isset($_SERVER)){ if(isset($_SERVER[HTTP_X_FO ...

  8. Postgresql迁移数据文件存放位置

    1. POSTGRESQL的安装 centos7 里面默认的pgsql的版本是 如果想用更高的版本需要执行以下如下的命令 rpm -ivh https://download.postgresql.or ...

  9. TP5 关联模型使用(嵌套关联、动态排序以及隐藏字段)

    在数据库设计中,常常会有如下这种关联模型,分类表中一条分类对应多个商品表中的商品 如果要获得分类表中每条分类 以及 对应的商品的信息,则需要先查询分类表中的数据,然后根据结果遍历查询商品表,最后把数据 ...

  10. java自定义注解学习(二)_注解详解

    上篇文章,我们简单的实现了一个自定义注解,相信大家对自定义注解有了个简单的认识,这篇,这样介绍下注解中的元注解和内置注解 整体图示 内置注解 @Override 重写覆盖 这个注解大家应该经常用到,主 ...