题面

luogu

题解

LCT

动态树Link-cut tree(LCT)总结

考虑先按边权排序,从小到大加边

如果构成一颗树了,就更新答案

当加入一条边,会形成环.

贪心地想,我们要最大边权-最小边权最小

最大边权固定就是新加入的这条边,我们要让最小边权尽量地大

那么我们可以去掉原先路径上最小的那一条边,这样一定不会差

以上,可以用LCT维护

ps:LCT只有点权,所以对于每条边,新建一个节点

Code

#include<bits/stdc++.h>
#define mp make_pair
#define LL long long
#define RG register
const int inf = 2147483647;
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
} const int N = 250000 + 10; struct node {
int v, m, fa, ch[2], w;//m为最小值,w为位置
bool rev;
}t[N];
int S[N], top, val[N];
set<pair<int, int> > Min;
void putrev(int x) {
swap(t[x].ch[0], t[x].ch[1]);
t[x].rev ^= 1;
}
void pushup(int x) {
t[x].m = val[x], t[x].w = x;
if (t[x].m > t[t[x].ch[0]].m && t[x].ch[0]) t[x].m = t[t[x].ch[0]].m, t[x].w = t[t[x].ch[0]].w;
if (t[x].m > t[t[x].ch[1]].m && t[x].ch[1]) t[x].m = t[t[x].ch[1]].m, t[x].w = t[t[x].ch[1]].w;
}
#define get(x) (t[t[x].fa].ch[1] == x)
bool isroot(int x) {
return (t[t[x].fa].ch[0] != x) && (t[t[x].fa].ch[1] != x);
}
void pushdown(int x) {
if (t[x].rev) {
t[x].rev = 0;
if (t[x].ch[0]) putrev(t[x].ch[0]);
if (t[x].ch[1]) putrev(t[x].ch[1]);
}
}
void rotate(int x) {
int k = get(x), y = t[x].fa, z = t[y].fa;
if (!isroot(y)) t[z].ch[get(y)] = x;
t[x].fa = z;
t[t[x].ch[k^1]].fa = y; t[y].ch[k] = t[x].ch[k^1];
t[y].fa = x; t[x].ch[k^1] = y;
pushup(y);
}
void splay(int x) {
S[top = 1] = x;
for (RG int i = x; !isroot(i); i = t[i].fa) S[++top] = t[i].fa;
for (RG int i = top; i; i--) pushdown(S[i]);
while (!isroot(x)) {
int y = t[x].fa;
if (!isroot(y))
(get(x) ^ get(y)) ? rotate(x) : rotate(y);
rotate(x);
}
pushup(x);
} void access(int x) {for (int y = 0; x; y = x, x = t[x].fa)splay(x), t[x].ch[1] = y, pushup(x);} void makeroot(int x) {access(x); splay(x); putrev(x);}
void link(int x, int y) {
makeroot(x);
t[x].fa = y;
}
void cut(int x, int y) {
makeroot(x);
access(y);
splay(y);
t[x].fa = t[y].ch[0] = 0; pushup(y);
}
void split(int x, int y) {makeroot(x); access(y); splay(y);} struct Node {
int u, v, w;
bool operator <(Node z) const {
return w < z.w;
}
}p[N];
int fa[N];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int main() {
int n, m, cnt = 0, ans = inf; read(n), read(m);
for (int i = 1; i <= m; i++)
read(p[i].u), read(p[i].v), read(p[i].w);
sort(p+1, p+1+m);
for (int i = 1; i <= n; i++) fa[i] = i, val[i] = inf;
for (int i = 1; i <= m; i++) {
int x = p[i].u, y = p[i].v;
if (x == y) continue;
val[i + n] = p[i].w;
if (find(x) != find(y)) {
cnt++; fa[find(y)] = find(x);
link(i + n, x); link(i + n, y);
Min.insert(mp(p[i].w, i));
} else {
split(x, y);
int wz = t[y].w;
cut(wz, p[wz - n].u); cut(wz, p[wz - n].v);
link(i + n, x); link(i + n, y);
Min.erase(mp(p[wz - n].w, wz - n));
Min.insert(mp(p[i].w, i));
}
if (cnt == n-1)
ans = min(ans, p[i].w - (Min.begin()->first));
}
printf("%d\n", ans);
return 0;
}

洛谷 P4234 最小差值生成树(LCT)的更多相关文章

  1. 洛谷P4234 最小差值生成树(LCT,生成树)

    洛谷题目传送门 和魔法森林有点像,都是动态维护最小生成树(可参考一下Blog的LCT总结相关部分) 至于从小到大还是从大到小当然无所谓啦,我是从小到大排序,每次枚举边,还没连通就连,已连通就替换环上最 ...

  2. 洛谷.4234.最小差值生成树(LCT)

    题目链接 先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差. 每次构成树时更新答案.答案就是当前边减去生成树 ...

  3. 洛谷P4234 最小差值生成树(lct动态维护最小生成树)

    题目描述 给定一个标号为从 11 到 nn 的.有 mm 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式:   第一行两个数 n, mn,m ,表示图的点和边的数量. ...

  4. 【刷题】洛谷 P4234 最小差值生成树

    题目描述 给定一个标号为从 \(1\) 到 \(n\) 的.有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式: 第一行两个数 \(n, m\) ,表示图的 ...

  5. [洛谷P4234] 最小差值生成树

    题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:求一棵生成树,其最大边权减最小边权最小 解题思路 和魔法森林非常像.先对所有边进行排序,每次加边的时候删除环上的最小 ...

  6. 洛谷4234最小差值生成树 (LCT维护生成树)

    这也是一道LCT维护生成树的题. 那么我们还是按照套路,先对边进行排序,然后顺次加入. 不过和别的题有所不同的是: 在本题中,我们需要保证LCT中正好有\(n-1\)条边的时候,才能更新\(ans\) ...

  7. P4234 最小差值生成树 LCT维护边权

    \(\color{#0066ff}{ 题目描述 }\) 给定一个标号为从 \(1\) 到 \(n\) 的.有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树. \(\color{#0 ...

  8. P4234 最小差值生成树

    题目 P4234 最小差值生成树 做法 和这题解法差不多,稍微变了一点,还不懂就直接看代码吧 \(update(2019.2):\)还是具体说一下吧,排序,直接加入,到了成环情况下,显然我们要把此边代 ...

  9. 【Luogu】P4234最小差值生成树(LCT)

    题目链接 能把LCT打得每个函数都恰有一个错误也是挺令我惊讶的. 本题使用LCT维护生成树,具体做法是对原图中的每个边建一个点,然后连边的时候相当于是将边的起点跟“边”这个点连起来,边的终点也跟它连起 ...

随机推荐

  1. Zedboard学习(四):PS+PL搭建SoC最小系统 标签: fpgazedboardxilinxsoczynq 2017-07-07 15:58 7人阅读

    zynq最核心的设计理念就是软件加硬件,即PS+PL.通过软硬件协同设计,结合了FPGA与双arm9内核,对于嵌入式拥有极大的优势. SoC:System on Chip的缩写,称为芯片级系统,也有称 ...

  2. 洛谷 P2569[SCOI2010]股票交易(动规+单调队列)

    //只能写出裸的动规,为什么会有人能想到用单调队列优化Orz 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测 ...

  3. 比较C++、Java、Delphi声明类对象时候的相关语法

    同学们在学习的时候经常会遇到一些问题,C++.Java.Delphi他们到底有什么不一样的呢?今天我们来比较C++.Java.Delphi声明类对象时候的相关语法.希望对大家有帮助! C++中创建对象 ...

  4. linux环境下搭建osm_web服务器一(Postgresql配置及osm2pgsql原始数据导入):

    Postgresql配置及osm2pgsql原始数据导入 2012年,Ubuntu 12.04LTS发布,又一个长效支持版,我们又该更新OpenStreetMap服务器了,这次,将详细在博客中记录配置 ...

  5. logback与log4j比较

    摘自:https://www.cnblogs.com/smile361/p/7592684.html logback与log4j比较 更快的执行速度: 基于我们先前在log4j上的工作,logback ...

  6. 3.3.6-1 ArrayBlockingQueue简单分析

    构造方法:public ArrayBlockingQueue(int capacity) { this(capacity, false); } public ArrayBlockingQueue(in ...

  7. Qt之QML开发常用知识

    小技巧: 1. QML的内部逻辑可以直接调试 2. ctrl+ alt + space,在写QML时,可以直接调出工具条 3. 属性以小写字母开发 4. 属性改变事件,基本都是on+Property+ ...

  8. 如何设置才能远程登录Mysql数据库

    可以在一台机器上访问另一台机器的MySQL,但是需要一些设置. 进入MySQL后,输入以下命令: GRANT ALL PRIVILEGES ON *.* TO 'tigase'@'%' IDENTIF ...

  9. Hadoop中Writable类

    1.Writable简单介绍 在前面的博客中,经常出现IntWritable,ByteWritable.....光从字面上,就可以看出,给人的感觉是基本数据类型 和 序列化!在Hadoop中自带的or ...

  10. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(8):装配SpringBean概述(如何合理使用装配级别)

    一. 装配Bean概述  关于如何将自己开发的Bean配置到Spring IoC容器中,大部分场景下,我们都会使用ApplicationContext的具体实现类,因为对应的Spring IoC容器功 ...