题面

题解

考虑最小化\(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的更多相关文章

  1. AT3611 Tree MST 点分治+最小生成树

    正解:点分治+最小生成树 解题报告: 传送门! 然后这题麻油翻译,,,所以这边的建议是先说下题意呢亲 所以题意大概就是说,给一棵n个节点的树,树上每个点都有个权值,然后构造一个完全图,(u,v)之间连 ...

  2. 【AtCoder3611】Tree MST(点分治,最小生成树)

    [AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...

  3. 【AT3611】Tree MST

    题目 这个题的输入首先就是一棵树,我们考虑一下点分 我们对于每一个分治重心考虑一下跨过这个分治重心的连边情况 就是把当前分治区域内所有的点向距离分治重心最近的点连边 考虑一下这个算法的正确性,如果我们 ...

  4. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  5. 题解-AtCoder Code-Festival2017 Final-J Tree MST

    Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...

  6. 最小生成树 (Minimum Spanning Tree,MST) --- Prim算法

    本文链接:http://www.cnblogs.com/Ash-ly/p/5409904.html 普瑞姆(Prim)算法: 假设N = (V, {E})是连通网,TE是N上最小生成树边的集合,U是是 ...

  7. 最小生成树 (Minimum Spanning Tree,MST) --- Kruskal算法

    本文链接:http://www.cnblogs.com/Ash-ly/p/5409265.html 引导问题: 假设要在N个城市之间建立通信联络网,则连通N个城市只需要N - 1条线路.这时,自然会考 ...

  8. HDU - 4786 Fibonacci Tree (MST)

    题意:给一张由白边和黑边构成的无向图,求是否存在一个生成树,使白边的数量为一个斐波那契数. 分析:白边权值为1,黑边权值为0.求出该图的最小生成树和最大生成树,若这两个值之间存在斐波那契数,则可以,若 ...

  9. @atcoder - CODE FESTIVAL 2017 Final - J@ Tree MST

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N 个点,第 i 点有一个点权 Xi,再给定一棵边带权的树 ...

随机推荐

  1. iOS开发NSDate、NSString、时间戳之间的转化

    //将UTCDate(世界标准时间)转化为当地时区的标准Date(钟表显示的时间) //NSDate *date = [NSDate date]; 2018-03-27 06:54:41 +0000 ...

  2. Kotlin入门(16)容器的遍历方式

    Kotlin号称全面兼容Java,于是乎Java的容器类仍可在Kotlin中正常使用,包括大家熟悉的队列ArrayList.映射HashMap等等.不过Kotlin作为一门全新的语言,肯定还是要有自己 ...

  3. 自定义合并列:el-table

    objectSpanMethod({ row, column, rowIndex, columnIndex }) {//合并规则 //当前行row.当前列column.当前行号rowIndex.当前列 ...

  4. python第五十三天--进程,协程.select.异步I/O...

    进程: #!usr/bin/env python #-*-coding:utf-8-*- # Author calmyan import multiprocessing,threading,time ...

  5. Linux记录屏幕输出log

    应用场景: 请专家通过Console处理问题时,保留console输出无疑是非常有意义的.一来可留着作为维护日志,二来可供事后学习. 最简洁的方式是通过系统自带的script命令去记录. $ scri ...

  6. Redhat 下 XAMPP 安装和部署 DVWA 教程

    XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建站集成软件包.这个软件包原来的名字是 LAMPP,但是为了避免误解,最新的几个版本就改名为 XAMPP 了.它可以在Windo ...

  7. January 07th, 2018 Week 01st Sunday

    To remember is to disengage from the present. 铭记过去就是放弃当下. To remember the past doesn't mean we would ...

  8. Alpha冲刺! Day3 - 砍柴

    Alpha冲刺! Day3 - 砍柴 今日已完成 晨瑶:补充安卓技能树: review接口文档:看了点七牛云安卓API. 昭锡:没有团队项目相关贡献. 永盛: API 文档基本完成:根据 API 文档 ...

  9. 基于jquery的从一个页面跳转到另一个页面的指定位置的实现代码

    比如 想跳到 mao.aspx 的页面 的div id="s" 的位置 那么 只用<a href="mao.aspx#s"> 就可实现跳转到指定位置 ...

  10. oracle 查询表中数据行(row)上最后的DML时间

    在这介绍Oracle 10G开始提供的一个伪列ORA_ROWSCN,它又分为两种模式一种是基于block这是默认的模式(块级跟踪):还有一种是基于row上,这种模式只能在建里表时指定ROWDEPEND ...