Brief Description

求一个无向图的严格次小生成树。

Algorithm Design

考察最小生成树的生成过程。对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大边,可以证明仍然满足生成树性质,而且这个生成树的大小一定不小于原生成树,那么枚举所有这样的非树边,尝试去替换,找到最小值就可以了。

那么问题就转化成了求树上两个点的最大/最小距离,这是树上倍增的经典应用,可以知道:

\[Max(x,i) = max(Max(x,i-1), Max(fa(x,i-1),i-1))
\]

我们可以通过递推用\(\Theta(nlogn)\)时间预处理出来这些信息。

问题解决了吗?还没有。原题要求严格小于原树。所以我们顺便预处理一下树上两个点的次大值就可以了。

Code

#include <algorithm>
#include <cstdio>
using std::max;
using std::min;
const int maxn = 100001;
const int maxm = 300001;
const int inf = 0x3f3f3f;
#define ll long long
int n, m, tot, cnt, mn = inf;
ll ans;
int f[maxn], head[maxn], deep[maxn], fa[maxn][17], d1[maxn][17], d2[maxn][17];
struct data {
int x, y, v;
bool sel;
bool operator<(const data b) const { return this->v < b.v; }
} a[maxm];
struct edge {
int to, next, v;
} e[maxn << 1];
void ins(int u, int v, int w) {
e[++cnt].to = v;
e[cnt].next = head[u];
e[cnt].v = w;
head[u] = cnt;
}
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
void dfs(int x, int f) {
for (int i = 1; i <= 16; i++) {
if (deep[x] < (1 << i))
break;
fa[x][i] = fa[fa[x][i - 1]][i - 1];
d1[x][i] = max(d1[x][i - 1], d1[fa[x][i - 1]][i - 1]);
if (d1[x][i - 1] == d1[fa[x][i - 1]][i - 1])
d2[x][i] = max(d2[x][i - 1], d2[fa[x][i - 1]][i - 1]);
else {
d2[x][i] = min(d1[x][i - 1], d1[fa[x][i - 1]][i - 1]);
d2[x][i] = max(d2[x][i], d2[x][i - 1]);
d2[x][i] = max(d2[x][i], d2[fa[x][i - 1]][i - 1]);
}
}
for (int i = head[x]; i; i = e[i].next) {
if (e[i].to != f) {
fa[e[i].to][0] = x;
d1[e[i].to][0] = e[i].v;
deep[e[i].to] = deep[x] + 1;
dfs(e[i].to, x);
}
}
}
int lca(int x, int y) {
if (deep[x] < deep[y])
std::swap(x, y);
int t = deep[x] - deep[y];
for (int i = 0; i <= 16; i++)
if (t & (1 << i))
x = fa[x][i];
for (int i = 16; i >= 0; i--)
if (fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
if (x == y)
return x;
return fa[x][0];
}
void cal(int x, int f, int v) {
int mx1 = 0, mx2 = 0;
int t = deep[x] - deep[f];
for (int i = 0; i <= 16; i++) {
if (t & (1 << i)) {
if (d1[x][i] > mx1) {
mx2 = mx1;
mx1 = d1[x][i];
}
mx2 = max(mx2, d2[x][i]);
x = fa[x][i];
}
}
if (mx1 != v)
mn = min(mn, v - mx1);
else
mn = min(mn, v - mx2);
}
void solve(int t, int v) {
int x = a[t].x, y = a[t].y, f = lca(x, y);
cal(x, f, v);
cal(y, f, v);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 1; i <= m; i++)
scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].v);
std::sort(a + 1, a + m + 1);
for (int i = 1; i <= m; i++) {
int p = find(a[i].x), q = find(a[i].y);
if (p != q) {
f[p] = q;
ans += a[i].v;
a[i].sel = 1;
ins(a[i].x, a[i].y, a[i].v);
ins(a[i].y, a[i].x, a[i].v);
tot++;
if (tot == n - 1)
break;
}
}
dfs(1, 0);
for (int i = 1; i <= m; i++)
if (!a[i].sel)
solve(i, a[i].v);
printf("%lld\n", ans + mn);
}

[bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca的更多相关文章

  1. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  2. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  3. bzoj1977 [BeiJing2010组队]次小生成树 Tree

    和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...

  4. bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 因为严格,所以要记录到 LCA 的一个次小值: 很快写好,然后改掉一堆错误后终于过了样 ...

  5. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

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

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

  7. 1977: [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...

  8. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

  9. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

随机推荐

  1. 纯HTML+CSS实现阿童木头像

    他有十万马力,能上天能入地:他分辨善恶,是勇敢正义化身:1963年,他登上荧幕,在日本创下了未曾有过的高收视率……他叫阿童木,一个纯真.善良.勇 敢的机器娃娃.“阿童木之父”手冢治虫曾说,将阿童木生日 ...

  2. Ubuntu16.04 + CUDA9.0 + cuDNN7.3 + Tensorflow-gpu-1.12 + Jupyter Notebook 深度学习环境配置

    目录 一.Ubuntu16.04 LTS系统的安装 二.设置软件源的国内镜像 1. 设置方法 2.关于ubuntu镜像的小知识 三.Nvidia显卡驱动的安装 1. 首先查看显卡型号和推荐的显卡驱动 ...

  3. 解决EasyUI DataGrid删除行失败的方法

    笔者最近在做一个项目的后台,用到了EasyUI的datagrid控件,并开启了行内编辑功能,实际上也就是使用了edatagird这个空间,引用了edatagrid.js,一切似乎都做的顺风顺水,添加数 ...

  4. [leetcode-644-Maximum Average Subarray II]

    Given an array consisting of n integers, find the contiguous subarray whose length is greater than o ...

  5. python之time和os模块

    1.time.time()获得的是一个时间戳,距离1970年以来多少秒 2.time.strftime(),按固定格式设置时间 import time print(time.localtime())# ...

  6. Windows下的Memcache安装与Java部署

    Windows下的Memcache安装: 1. 下载memcached的windows稳定版,解压放某个盘下面,比如在c:\memcached 2. 在终端(也即cmd命令界面)下输入 ‘c:\mem ...

  7. Spark程序

    Spark认识&环境搭建&运行第一个Spark程序 2017-07-09 17:17 by 牛仔裤的夏天, 181 阅读, 0 评论, 收藏, 编辑 摘要:Spark作为新一代大数据计 ...

  8. LeetCode -- Best Time to Buy and Sell Stock系列

    Question: Best Time to Buy and Sell Stock Say you have an array for which the ith element is the pri ...

  9. 你是否彻底了解margin属性?

    写css,你少不了与margin打交道.你真的了解margin吗?你知道margin有什么特性吗?你知道什么是垂直外边距合并?margin在块元素.内联元素中的区别?什么时候该用padding而不是m ...

  10. Spring源码解析-事件

    Spring事件的组件 主要是3个组件: 1.ApplicationEvent   事件 2.ApplicationListener 监听器,对事件进行监听 3.ApplicationEventMul ...