题目类型:\(LCT\)动态维护最小生成树

传送门:>Here<

题意:求一棵生成树,其最大边权减最小边权最小

解题思路

和魔法森林非常像。先对所有边进行排序,每次加边的时候删除环上的最小边即可

正确性好像很显然,显然由于每一条边一定会被加入,所以最大边权是可以确定的,然后在所有小于等于自己的边权中已经尽量去除了最小的,这是一个贪心

问题在于,由于这里和魔法森林不一样,不要求一个路径上的,而是整颗生成树。因此单单利用\(split\)来维护好像有点棘手。

我们考虑我们是按从小到大的顺序加边的,而每一次又有环内最小的边。有点像一个队列……我们可以用一个队列来维护所有当前在最小生成树中的边,每一次更新队尾。由于是从小到大的,因此队头就是最大的,队尾就是最小的。由于每一次有可能有最小值出队,所以需要向后维护一下。如果出队的不是最小值,那么根本就不用去管。

至于有哪些边在最小生成树内,用个\(bool\)的桶来维护一下就好了,非常\(eazy\)

反思

这题竟然有自环……

另外,在这道题目里,\(splay\)应该维护最大值。而最大值在打擂的时候要注意儿子的存在问题。或者我们可以将\(val[0]\)设为无限大。

Code

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 50010;
const int MAXM = 200010;
const int MAXS = MAXN + MAXM;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Edge{
int x,y,v;
}e[MAXM];
int N,M,ans(INF),MX,cnt;
int val[MAXS],mn[MAXS],q[MAXM],top,head=1;
bool used[MAXM];
struct LinkCutTree{
int ch[MAXS][2],fa[MAXS];
bool tag[MAXS];
inline bool rson(int f, int x){
return ch[f][1] == x;
}
inline bool isroot(int x){
return ch[fa[x]][rson(fa[x],x)]!=x;
}
inline void pushup(int x){
mn[x] = x;
if(val[mn[ch[x][0]]] < val[mn[x]] && ch[x][0]) mn[x] = mn[ch[x][0]];
if(val[mn[ch[x][1]]] < val[mn[x]] && ch[x][1]) mn[x] = mn[ch[x][1]];
}
inline void rotate(int x){
int f = fa[x], gf = fa[f];
bool p = rson(f,x), q = !p;
if(!isroot(f)) ch[gf][rson(gf,f)] = x; fa[x] = gf;
ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
ch[x][q] = f, fa[f] = x;
pushup(f), pushup(x);
}
void reverse(int x){
if(!isroot(x)) reverse(fa[x]);
if(!tag[x]) return;
tag[x] = 0;
swap(ch[x][0], ch[x][1]);
tag[ch[x][0]] ^= 1, tag[ch[x][1]] ^= 1;
}
inline void splay(int x){
for(reverse(x); !isroot(x); rotate(x)){
if(isroot(fa[x])){ rotate(x); break; }
if(rson(fa[fa[x]],fa[x]) ^ rson(fa[x],x)) rotate(x); else rotate(fa[x]);
}
}
inline void access(int x){
for(int y = 0; x; y=x, x = fa[x]) splay(x), ch[x][1] = y, pushup(x);
}
inline void mroot(int x){
access(x);
splay(x);
tag[x] ^= 1;
}
inline int findroot(int x){
access(x), splay(x);
while(ch[x][0]) x = ch[x][0];
return x;
}
inline void split(int x, int y){
mroot(x);
access(y);
splay(y);
}
inline void link(int x, int y){
if(findroot(x) == findroot(y)) return;
mroot(x);
fa[x] = y;
}
inline void cut(int x, int y){
split(x,y);
if(ch[y][0] != x || ch[x][1] != 0) return;
ch[y][0] = fa[x] = 0;
}
inline void debug(){
for(int i = 1; i <= M+N; ++i){
printf("%d ls=%d rs=%d fa=%d min=%d %d\n",i,ch[i][0],ch[i][1],fa[i],val[mn[i]],mn[i]);
}
}
}qxz;
inline bool cmp(const Edge& a, const Edge& b){
return a.v < b.v;
}
int main(){
// freopen(".in","r",stdin);
N = read(), M = read();
for(int i = 1; i <= M; ++i){
e[i].x = read(), e[i].y = read(), e[i].v = read();
}
sort(e+1, e+M+1, cmp);
for(int i = 1; i <= N; ++i) val[i] = INF;
for(int i = N+1; i <= N+M; ++i) val[i] = e[i-N].v;
for(int i = 1; i <= N+M; ++i) mn[i] = i;
for(int i = 1; i <= M; ++i){
if(e[i].x == e[i].y) continue;
if(qxz.findroot(e[i].x) != qxz.findroot(e[i].y)){
qxz.link(e[i].x, N+i);
qxz.link(e[i].y, N+i);
MX = e[i].v;
++cnt;
used[i] = 1;
q[++top] = i;
}
else{
qxz.split(e[i].x, e[i].y);
int temp = mn[e[i].y]-N;
used[temp] = 0;
used[i] = 1;
qxz.cut(e[temp].x, temp+N);
qxz.cut(e[temp].y, temp+N);
qxz.link(e[i].x, N+i);
qxz.link(e[i].y, N+i);
q[++top] = i;
}
if(cnt == N-1){
qxz.split(1, N);
while(!used[q[head]]) ++head;
ans = Min(ans, val[q[top]+N] - val[q[head]+N]);
}
}
printf("%d", ans);
}

[洛谷P4234] 最小差值生成树的更多相关文章

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

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

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

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

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

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

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

    题面 luogu 题解 LCT 动态树Link-cut tree(LCT)总结 考虑先按边权排序,从小到大加边 如果构成一颗树了,就更新答案 当加入一条边,会形成环. 贪心地想,我们要最大边权-最小边 ...

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

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

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

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

  7. P4234 最小差值生成树

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

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

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

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

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

随机推荐

  1. 在android studio中配置运行时签名

    做项目的时候,有时需要用到第三方接口,而基本第三方接口都是要求我们要先进行签名.结果每次调试都得手动进行签名一次,实在麻烦.所以android studio提供了一种在运行的时候自动进行签名的方法,在 ...

  2. 以太坊智能合约 Solidity 的常用数据类型介绍

    目录 目录 1.数组 1.1.对数组的增删改查操作. 2.String.Bytes.Mapping的使用 3.Enums 和 Structs 的简单应用 4.Ether 单位和 Time 单位 5.A ...

  3. spring学习总结——高级装配学习三(Bean的作用域)

    一.bean的作用域 在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的.也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同 ...

  4. bootstrap,bootstrap-table,bootstrapValidator,animate,layer配合起来搞事情

    资源准备(just download) bootstrap: http://www.bootcss.com/ bootstrap-table: http://bootstrap-table.wenzh ...

  5. SQLServer之PRIMARY KEY约束

    PRIMARY KEY约束添加规则 1.在表中常有一列或多列的组合,其值能唯一标识表中的每一行,这样的一列或多列成为表的主键(PrimaryKey). 2.一个表只能有一个主键,而且主键约束中的列不能 ...

  6. Redis管道和发布订阅

    管道:原子性执行命令 ''' redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作, 如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定 ...

  7. C# 里面swith的或者

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  8. HBase工具:如何查看HBase的HFile

    root@root:~/Desktop/sourceCodes/hbase-2.1.1/bin# ./hbase Usage: hbase [<options>] <command& ...

  9. 前端面试回顾---javascript的面向对象

    转:https://segmentfault.com/a/1190000011061136 前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用 ...

  10. flex布局justify-content属性和align-items属性设置

    前言: flex最常用的就是justify-content和align-items了,这里把这两个属性介绍下,大家更多关于flex布局可以查看阮一峰的日志,写的非常清楚! 阮一峰flex布局的日志:h ...