树的重心的定义:

树若以某点为根,使得该树最大子树的结点数最小,那么这个点则为该树的重心,一棵树可能有多个重心。

树的重心的性质:

1、树上所有的点到树的重心的距离之和是最短的,如果有多个重心,那么总距离相等。

2、插入或删除一个点,树的重心的位置最多移动一个单位。

3、若添加一条边连接2棵树,那么新树的重心一定在原来两棵树的重心的路径上。

当然,这题我们只需要用到第一条性质。

怎么求树的重心:

定义几个数组:\(f[u]\)表示以u为根的总距离,\(size[u]\)表示以u为根的子树的大小(结点数,此题每个点要乘以权值,下文结点数均指此)。

显然,\(ans=min(f[i],1<=i<=n)\)

首先我们任意以一个点为根dfs一遍,求出以该点为根的总距离。方便起见,我们就以1为根。

接下来就是转移,对于每个u能达到的点v,有:

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

怎么来的呢?试想,当根从u变为v的时候,v的子树的所有节点原本的距离要到\(u\),现在只要到\(v\)了,每个结点的距离都减少1,那么总距离就减少\(size[v]\),同时,以v为根的子树以外的所有节点,原本只要到\(u\)就行了,现在要到\(v\),每个节点的路程都增加了1,总路程就增加了\(size[1]-size[v]\),其中\(size[1]\)就是我们预处理出来的整棵树的大小,减去\(size[v]\)就是除以v为根的子树以外的结点数。

最后取最小值,得解。时间复杂度\(O(n)\)

附上代码:

#include <cstdio>
#define rep(i, m, n) for(register int i = m; i <= n; ++i)
#define INF 2147483647
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
using namespace std;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
const int MAXN = 10010;
struct Edge{
int next, to;
}e[MAXN << 1];
int head[MAXN], num, w[MAXN], n, size[MAXN];
long long ans = INF, f[MAXN];
inline void Add(int from, int to){
e[++num].to = to;
e[num].next = head[from];
head[from] = num;
}
void dfs(int u, int fa, int dep){ //预处理f[1]和size
size[u] = w[u];
for(int i = head[u]; i; i = e[i].next){
if(e[i].to != fa)
dfs(e[i].to, u, dep + 1), size[u] += size[e[i].to];
}
f[1] += w[u] * dep;
}
void dp(int u, int fa){ //转移
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
f[e[i].to] = f[u] + size[1] - size[e[i].to] * 2, dp(e[i].to, u);
ans = min(ans, f[u]); //取最小值
}
int a, b;
int main(){
//Open("hospital");
ans *= ans;
n = read();
rep(i, 1, n){
w[i] = read();
a = read(); b = read();
if(a) Add(i, a), Add(a, i);
if(b) Add(i, b), Add(b, i);
}
dfs(1, 0, 0);
dp(1, 0);
printf("%lld\n", ans);
//Close;
return 0;
}

【洛谷 P1364】医院设置(树的重心)的更多相关文章

  1. 【模板】树的重心 洛谷P1364 医院设置

    P1364 医院设置 题目描述 设有一棵二叉树,如图: 其中,圈中的数字表示结点中居民的人口.圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接 ...

  2. 洛谷 P1364 医院设置

    题目描述 设有一棵二叉树,如图: 其中,圈中的数字表示结点中居民的人口.圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为l.如上 ...

  3. 洛谷P1364 医院设置(Floyd)

    题目描述 设有一棵二叉树,如图: 其中,圈中的数字表示结点中居民的人口.圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为l.如上 ...

  4. 洛谷P1364 医院设置

    LITTLESUN的第一道图论,撒花~~ 题目链接 这道题是Floyd的板子题 注意对于矩阵图的初始值赋值要全部赋值成最大值 十六进制的最大值表示方式是0x3f3f3f3f memset(G,0x3f ...

  5. 洛谷P1395 会议 (树的重心)

    这道题考察了树的重心的性质,所有点到中心的距离之和是最小的,所以我们一遍dfs求出树的重心,在跑一次dfs统计距离之和. 1 #include<bits/stdc++.h> 2 using ...

  6. P1364 医院设置(树型结构)

    传送门闷闷闷闷闷闷 ~~放一个可爱的输入框.~~ 考虑在O(n)的时间内求数以每个节点为医院的距离和. \(设想一下,如果我们已知以1为根节点的距离和f[1],如何求出子节点呢?\) 当医院从1转换到 ...

  7. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  8. 【BZOJ2830/洛谷3830】随机树(动态规划)

    [BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...

  9. P1364 医院设置 (补锅,memset初始化较大值不可用0x7fffffff )

    P1364 医院设置 题解 弗洛伊德水过 注意初始化一个大数 0x3f 可以,0x5f 好像也可以,但是0x7fffffff 我是真的炸了,初始化为-1 (后面补锅有详细解释) 代码 #include ...

随机推荐

  1. 手把手教你写css3通用动画

    之前接了几个微信里的项目,类似电子邀请函,什么分析报告这样的项目, 对css3动画要求十分高,每个页面客户几乎都有天马行空的想法,或者说设计师有这样的想法.众所周知css3里的keyframe写好了就 ...

  2. 「Haskell 学习」二 类型和函数(上)

    随着学习的深入,笔记会补充和修订.当然,这个补充修订也许会鸽,但我一定会坚持写完. 这个笔记假定你至少学过C/C++及Python,或与这两种语言类型相同的语言. 类型系统概述 “Haskell’s ...

  3. gitbash避免每次push都输入密码

    gitbash每次提交都要输密码真有点头疼,所以就: 1 创建验证文件:touch  .git-credentials(windows) 2 编辑验证文件:vim  .git-credentials ...

  4. Ajax跨域请求解决方式

    前端 jQuery方式 .ajax({ type: "POST", url: "http://xxx.com/api/test", dataType: 'jso ...

  5. CentOS环境配置Hadoop(一)

    配置Linux开发环境(hadoop-2.6.4) 一.准备工具 VMware-workstation-10.0.1注册机 CentOS-6.5-x86_64-bin-DVD1 jdk-7u79-li ...

  6. 局部敏感哈希LSH

    之前介绍了Annoy,Annoy是一种高维空间寻找近似最近邻的算法(ANN)的一种,接下来再讨论一种ANN算法,LSH局部敏感哈希. LSH的基本思想是: 原始空间中相邻的数据点通过映射或投影变换后, ...

  7. DP入门(4)——线性结构上的动态规划

    一.最长上升子序列(LIS) 给定n个整数A1,A2,…,An,按从左到右的顺序选出尽量多的整数,组成一个上升子序列(子序列可以理解为:删除0个或多个数,其他数的顺序不变).例如序列1,6,2,3,7 ...

  8. Unity UGUI 图片 轴对称效果 减少资源

    制作UI的过程中,为了节省资源,对称的图一般美术切一半给我们 手动拼图 有时会出现拼接处出现裂缝或重叠 调整大小时也不方便 得一块一块调整 所以就用BaseMeshEffect 的ModifyMesh ...

  9. 文件系统中 atime,lazytime,relatime 详聊

    atime,ctime,mtime是文件inode的三个时间戳,分别表示文件最近一次的访问时间:inode本身的更改(changed)时间:文件数据的更改(modify)时间:这几个概念还是很好区分. ...

  10. [STL] STL各容器实现原理

    STL共有六大组件1.容器 2.算法 3.迭代器 4.仿函数 6.适配器 STL容器的实现原理 STL来管理数据十分方便,省去了我们自己构建数据结构的时间.其实,STL的实现也是基于我们常见的数据结构 ...