【洛谷 P2726】 [SHOI2005]树的双中心(树的重心)
先考虑一个\(O(N^2)\)做法。
设选的两个点为\(x,y\),则一定可以将树分成两个集合\(A,B\),使得\(A\)集合所有点都去\(x\),\(B\)集合所有点都去\(y\),而这两个集合的分界点就是树上的一条边。于是考虑枚举断哪条边,然后对两边分别跑一遍带权树的重心,统计答案加起来取最小值就行了。
现在进行优化,求树的重心的方法可以参考医院设置。
以\(1\)为根建树,\(f[u]\)表示所有点到\(u\)的总距离。(人数乘以距离)
转移方程是:
\]
可以发现,只有当\(size[v]*2>size[1]\)时\(v\)比\(u\)更优,而且满足\(size[v]*2>size[1]\)的\(v\)数量\(<=1\)。
所以我们可以预处理出每个点的子树大小最大的儿子和次大的儿子,每次断边时自下而上修改其所有祖先的\(size\)大小,这时最大儿子可能变小,进而被次大儿子替代,直接判断一下然后走此时的大儿子就行。易得时间复杂度为\(O(NH)\),这也就是题中提到树的高度不超过\(100\)的原因吧。
#include <cstdio>
#include <algorithm>
#define INF 2147483647
using namespace std;
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
int s, w; char ch;
inline int read(){
s = 0; ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar();}
return s;
}
const int MAXN = 100010;
struct Edge{
int next, to;
}e[MAXN << 1];
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;
inline void Add(int from, int to){
e[++num].to = to; e[num].next = head[from]; head[from] = num;
e[++num].to = from; e[num].next = head[to]; head[to] = num;
}
int getsize(int u, int fa){
size[u] = a[u]; f[u] = fa; dep[u] = dep[fa] + 1;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa){
getsize(e[i].to, u);
size[u] += size[e[i].to];
val[u] += val[e[i].to] + size[e[i].to];
if(size[e[i].to] > size[son[u]]){
Sson[u] = son[u];
son[u] = e[i].to;
}
else if(size[e[i].to] > size[Sson[u]])
Sson[u] = e[i].to;
}
}
void getans(int u, int now, int all, int &res){
res = min(res, now);
int v = son[u];
if(v == cut || size[Sson[u]] > size[son[u]]) v = Sson[u]; //如果size变化后次大大于最大
if(!v) return;
if(size[v] * 2 > all) getans(v, now + all - size[v] - size[v], all, res); //如果size[v]*2<=all就没有继续往下走的意义了,因为此时u一定最优
}
int solve(int u){
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != f[u]){
cut = e[i].to; //断边
A = B = INF;
for(int now = u; now; now = f[now]) size[now] -= size[e[i].to]; //自下而上修改其父亲size
getans(1, val[1] - val[e[i].to] - dep[e[i].to] * size[e[i].to], size[1], A);
getans(e[i].to, val[e[i].to], size[e[i].to], B); //求两个集合的答案
ans = min(ans, A + B);
for(int now = u; now; now = f[now]) size[now] += size[e[i].to]; //回溯
solve(e[i].to);
}
}
int main(){
//Open("practice");
n = read(); dep[0] = -1;
for(int i = 1; i < n; ++i) Add(read(), read());
for(int i = 1; i <= n; ++i) a[i] = read();
getsize(1, 0);
solve(1);
printf("%d\n", ans);
return 0;
}
【洛谷 P2726】 [SHOI2005]树的双中心(树的重心)的更多相关文章
- 题解-SHOI2005 树的双中心
SHOI2005 树的双中心 给树 \(T=(V,E)(|V|=n)\),树高为 \(h\),\(w_u(u\in V)\).求 \(x\in V,y\in V:\left(\sum_{u\in V} ...
- BZOJ3302: [Shoi2005]树的双中心
BZOJ3302: [Shoi2005]树的双中心 https://lydsy.com/JudgeOnline/problem.php?id=3302 分析: 朴素算法 : 枚举边,然后在两个连通块内 ...
- 【BZOJ3302】[Shoi2005]树的双中心 DFS
[BZOJ3302][Shoi2005]树的双中心 Description Input 第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号.接下来N-1行,每行两个整 ...
- 洛谷 P3377 【模板】左偏树(可并堆)
洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...
- 洛谷P3377 【模板】左偏树(可并堆) 题解
作者:zifeiy 标签:左偏树 这篇随笔需要你在之前掌握 堆 和 二叉树 的相关知识点. 堆支持在 \(O(\log n)\) 的时间内进行插入元素.查询最值和删除最值的操作.在这里,如果最值是最小 ...
- 【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站
[题意]给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小.n<=50000,h<=100. [算法]树的重心 [题解]代码参考自:cgh_Andy 观察 ...
- 洛谷P3434 [POI2006]KRA-The Disks(线段树)
洛谷题目传送门 \(O(n)\)的正解算法对我这个小蒟蒻真的还有点思维难度.洛谷题解里都讲得很好. 考试的时候一看到300000就直接去想各种带log的做法了,反正不怕T...... 我永远只会有最直 ...
- 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)
LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...
- 洛谷AT2046 Namori(思维,基环树,树形DP)
洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
随机推荐
- CentOS-7.x Yum Repo Mirror
一. 环境 1.1 主机信息 主机 OS Storage 备注 100.64.140.101 centos 7.6 /dev/sdb > 100GB 1.selinux disable; 2.放 ...
- PAT甲题题解-1034. Head of a Gang (30)-并查集
给出n和k接下来n行,每行给出a,b,c,表示a和b之间的关系度,表明他们属于同一个帮派一个帮派由>2个人组成,且总关系度必须大于k.帮派的头目为帮派里关系度最高的人.(注意,这里关系度是看帮派 ...
- eclipse实现热部署和热启动
不用每次修改一个class文件就要重启tomcat这么麻烦: http://blog.csdn.net/fuzhongyu2/article/details/52073050
- linux 常用命令-用户、用户组管理
注:本篇只涉及常用命令,全部命令可以通过help帮助查看. (1)type useradd #查看命令属于内部命令还是外部命令,内部命令是嵌在linux的shell中,外部命令存储在路径中 (2) ...
- OpenFlow PacketOut消息机制
OpenFlow PacketOut消息机制 前言 由于最近实验的进行,遇到一个比较棘手的问题,就是利用控制器主动发送packet消息的问题,期间遇到一些问题,后来在RYU群中得到群友左木的帮助成功解 ...
- 【助教】浅析log4j的使用
有不少童鞋私信我一些在写代码时候遇到的问题,但是无法定位问题出在哪里,也没有日志记录,实际上,写日志是开发项目过程中很重要的一个环节,很多问题都可以从日志中找到根源,从而定位到出错位置,为解决问题提供 ...
- ElasticSearch 2 (14) - 深入搜索系列之全文搜索
ElasticSearch 2 (14) - 深入搜索系列之全文搜索 摘要 在看过结构化搜索之后,我们看看怎样在全文字段中查找相关度最高的文档. 全文搜索两个最重要的方面是: 相关(relevance ...
- 第十一周(11.24-12.01)----ptim测试程序运行速度
我在dos下用ptime指令对分数运算(http://www.cnblogs.com/YangXiaomoo/p/6095583.html)的运行时间进行了测试.测试结果一般都在0.212-0.217 ...
- phpStudy-坑爹的数据库管理器-phpMyAdmin的默认用户名和密码
在这里我必须承认自己的弱智,第一次使用phpMyAdmin竟然搞了10分钟才进去!!! 要使用默认的用户名和密码: 用户名:root 密码:root 尼玛!坑爹啊!不说清楚让我百度了半天!!!!
- Delphi字符串转日期,强大到窒息,VarToDateTime解决了困扰很久的小问题
procedure THRForm.Button1Click(Sender: TObject); var D:TDateTime; s:string; begin D:=VarToDateTime(' ...