AT3611 Tree MST
题面
题解
考虑最小化\(dis(x, y)\)
这里需要对一种奇怪的最小生成树算法:Boruvka算法有深刻的理解。
考虑该算法的执行过程,我们可以考虑进行点分治,每次找到离分治重心最近的点,然后将分治重心的所有子树的点全部向这个点连边,边数是\(\mathrm{O}(\)子树大小\()\)的,所以总边数在\(\mathrm{O}(n\log_2n)\)级别,最后将这些边跑kruskal求出最小生成树就可以了,总复杂度\(\mathrm{O}(n\log_2^2 n)\)。
代码
#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<algorithm>
#define RG register
inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
}
const int maxn(2e5 + 10);
struct edge { int next, to, dis; } e[maxn << 1];
int head[maxn], e_num;
inline void add_edge(int from, int to, int dis)
{
e[++e_num] = (edge) {head[from], to, dis};
head[from] = e_num;
}
struct node { int x, y; long long w; } a[maxn * 50];
inline int cmp(const node &lhs, const node &rhs) { return lhs.w < rhs.w; }
int n, m, W[maxn], SIZE, size[maxn], root, _max, vis[maxn];
void getRoot(int x, int fa)
{
int max = 0; size[x] = 1;
for(RG int i = head[x]; i; i = e[i].next)
{
int to = e[i].to; if(vis[to] || to == fa) continue;
getRoot(to, x); size[x] += size[to]; max = std::max(max, size[to]);
}
max = std::max(max, SIZE - size[x]);
if(max < _max) _max = max, root = x;
}
int pos; long long val;
void dfs(int x, int fa, long long dep)
{
if(dep + W[x] < val) val = dep + W[x], pos = x;
for(RG int i = head[x]; i; i = e[i].next)
{
int to = e[i].to; if(vis[to] || to == fa) continue;
dfs(to, x, dep + e[i].dis);
}
}
void link(int x, int fa, long long dep)
{
a[++m] = (node) {x, pos, val + W[x] + dep};
for(RG int i = head[x]; i; i = e[i].next)
{
int to = e[i].to; if(vis[to] || to == fa) continue;
link(to, x, dep + e[i].dis);
}
}
void solve(int x)
{
vis[x] = 1; val = LLONG_MAX >> 1; pos = 0;
dfs(x, 0, 0); link(x, 0, 0);
for(RG int i = head[x]; i; i = e[i].next)
{
int to = e[i].to; if(vis[to]) continue;
SIZE = _max = size[to]; getRoot(to, x);
solve(root);
}
}
long long ans; int fa[maxn];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main()
{
SIZE = _max = n = read();
for(RG int i = 1; i <= n; i++) W[i] = read();
for(RG int i = 1, x, y, z; i < n; i++)
x = read(), y = read(), z = read(),
add_edge(x, y, z), add_edge(y, x, z);
getRoot(1, 0); solve(root);
std::sort(a + 1, a + m + 1, cmp);
for(RG int i = 1; i <= n; i++) fa[i] = i;
for(RG int i = 1; i <= m; i++)
{
if(find(a[i].x) == find(a[i].y)) continue;
fa[find(a[i].x)] = find(a[i].y); ans += a[i].w;
}
printf("%lld\n", ans);
return 0;
}
AT3611 Tree MST的更多相关文章
- AT3611 Tree MST 点分治+最小生成树
正解:点分治+最小生成树 解题报告: 传送门! 然后这题麻油翻译,,,所以这边的建议是先说下题意呢亲 所以题意大概就是说,给一棵n个节点的树,树上每个点都有个权值,然后构造一个完全图,(u,v)之间连 ...
- 【AtCoder3611】Tree MST(点分治,最小生成树)
[AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...
- 【AT3611】Tree MST
题目 这个题的输入首先就是一棵树,我们考虑一下点分 我们对于每一个分治重心考虑一下跨过这个分治重心的连边情况 就是把当前分治区域内所有的点向距离分治重心最近的点连边 考虑一下这个算法的正确性,如果我们 ...
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...
- 题解-AtCoder Code-Festival2017 Final-J Tree MST
Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...
- 最小生成树 (Minimum Spanning Tree,MST) --- Prim算法
本文链接:http://www.cnblogs.com/Ash-ly/p/5409904.html 普瑞姆(Prim)算法: 假设N = (V, {E})是连通网,TE是N上最小生成树边的集合,U是是 ...
- 最小生成树 (Minimum Spanning Tree,MST) --- Kruskal算法
本文链接:http://www.cnblogs.com/Ash-ly/p/5409265.html 引导问题: 假设要在N个城市之间建立通信联络网,则连通N个城市只需要N - 1条线路.这时,自然会考 ...
- HDU - 4786 Fibonacci Tree (MST)
题意:给一张由白边和黑边构成的无向图,求是否存在一个生成树,使白边的数量为一个斐波那契数. 分析:白边权值为1,黑边权值为0.求出该图的最小生成树和最大生成树,若这两个值之间存在斐波那契数,则可以,若 ...
- @atcoder - CODE FESTIVAL 2017 Final - J@ Tree MST
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N 个点,第 i 点有一个点权 Xi,再给定一棵边带权的树 ...
随机推荐
- iOS开发NSDate、NSString、时间戳之间的转化
//将UTCDate(世界标准时间)转化为当地时区的标准Date(钟表显示的时间) //NSDate *date = [NSDate date]; 2018-03-27 06:54:41 +0000 ...
- Kotlin入门(16)容器的遍历方式
Kotlin号称全面兼容Java,于是乎Java的容器类仍可在Kotlin中正常使用,包括大家熟悉的队列ArrayList.映射HashMap等等.不过Kotlin作为一门全新的语言,肯定还是要有自己 ...
- 自定义合并列:el-table
objectSpanMethod({ row, column, rowIndex, columnIndex }) {//合并规则 //当前行row.当前列column.当前行号rowIndex.当前列 ...
- python第五十三天--进程,协程.select.异步I/O...
进程: #!usr/bin/env python #-*-coding:utf-8-*- # Author calmyan import multiprocessing,threading,time ...
- Linux记录屏幕输出log
应用场景: 请专家通过Console处理问题时,保留console输出无疑是非常有意义的.一来可留着作为维护日志,二来可供事后学习. 最简洁的方式是通过系统自带的script命令去记录. $ scri ...
- Redhat 下 XAMPP 安装和部署 DVWA 教程
XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建站集成软件包.这个软件包原来的名字是 LAMPP,但是为了避免误解,最新的几个版本就改名为 XAMPP 了.它可以在Windo ...
- January 07th, 2018 Week 01st Sunday
To remember is to disengage from the present. 铭记过去就是放弃当下. To remember the past doesn't mean we would ...
- Alpha冲刺! Day3 - 砍柴
Alpha冲刺! Day3 - 砍柴 今日已完成 晨瑶:补充安卓技能树: review接口文档:看了点七牛云安卓API. 昭锡:没有团队项目相关贡献. 永盛: API 文档基本完成:根据 API 文档 ...
- 基于jquery的从一个页面跳转到另一个页面的指定位置的实现代码
比如 想跳到 mao.aspx 的页面 的div id="s" 的位置 那么 只用<a href="mao.aspx#s"> 就可实现跳转到指定位置 ...
- oracle 查询表中数据行(row)上最后的DML时间
在这介绍Oracle 10G开始提供的一个伪列ORA_ROWSCN,它又分为两种模式一种是基于block这是默认的模式(块级跟踪):还有一种是基于row上,这种模式只能在建里表时指定ROWDEPEND ...