题目类型:\(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. pd_ds中的hash

    前言 在c++的STL中,提供了一种hash函数,其用法和map是几乎一样的,但是速度却能快接近一倍 使用方法 需要的头文件 #include<ext/pb_ds/assoc_container ...

  2. Android 简单登陆 涉及 Button CheckBox TextView EditText简单应用

    GitHub地址:https://github.com/1165863642/LoginDemo 直接贴代码<?xml version="1.0" encoding=&quo ...

  3. 小学生四则运算(java编程)201571030135

    任务1源码在Github的仓库主页链接地址: https://github.com/zhanghh2018/Four-primary-school-pupils 需求分析: 作业总体效果:随机产生n道 ...

  4. Prometheus Operator - 每天5分钟玩转 Docker 容器技术(177)

    前面我们介绍了 Kubernetes 的两种监控方案 Weave Scope 和 Heapster,它们主要的监控对象是 Node 和 Pod.这些数据对 Kubernetes 运维人员是必须的,但还 ...

  5. linux备份还原命令

    使用范围:1.可以作为系统还原点,还原到备份时的状态 2.系统完全损坏后无法启动,通过引导盘恢复 一.备份还原系统命令 方法一: 备份:tar cvpzf backup.tgz --exclude=/ ...

  6. Redhat安装Oracle 11g (转)

    1.1     安装前准备 1.1.1     修改操作系统核心参数 在Root用户下执行以下步骤: 1.1.1.1 修改/etc/security/limits.conf文件 输入命令:vi /et ...

  7. CentOS7 Docker私有仓库搭建及删除镜像 【转】

    文章来源:centos7 Docker私有仓库搭建及删除镜像 如果不想用私有镜像库,你可以用docker的库 https://hub.docker.com 环境准备 环境:两个装有Docker 17. ...

  8. Docker: Harbor一些小知识

    镜像文件上传到私有仓库harbor后,镜像的物理存储位置在哪里? 这些信息记录在docker-compose.yml里,通过观察发现 镜像存储在了宿主机的 volumes: - /data/regis ...

  9. javascript基础之函数

    javascript的函数定义与python有很大的区别,的记住格式就好,下面请看代码 // 函数 // 简单定义 function func() { console.log('hello word' ...

  10. Python爬虫 selenium

    库的安装 pip3 install selenium 声明浏览器对象 from selenium import webdriver browser = webdriver.Chrome() brows ...