洛谷P4234 最小差值生成树(lct动态维护最小生成树)
题目描述
给定一个标号为从 11 到 nn 的、有 mm 条边的无向图,求边权最大值与最小值的差值最小的生成树。
输入输出格式
输入格式:
第一行两个数 n, mn,m ,表示图的点和边的数量。
第二行起 mm 行,每行形如 u_i, v_i, w_iui,vi,wi ,代表 u_iui 到 v_ivi 间有一条长为 w_iwi 的无向边。
输出格式:
输出一行一个整数,代表你的答案。
数据保证存在至少一棵生成树。
输入输出样例
说明
对于 30% 的数据,满足 1 \leq n \leq 100, 1 \leq m \leq 10001≤n≤100,1≤m≤1000
对于 97% 的数据,满足 1 \leq n \leq 500, 1 \leq m \leq 1000001≤n≤500,1≤m≤100000
对于 100% 的数据,满足 1 \leq n \leq 50000, 1 \leq m \leq 200000, 1 \leq w_i \leq 100001≤n≤50000,1≤m≤200000,1≤wi≤10000
题解:有自环是真的毒瘤……反正思路是从大到小枚举每条边作为最小边构成的生成树,然后显然他要加进去就要把原环上最大值扔掉,这样子动态加边删边,就可以搞出答案了
还有个问题是怎么维护最小生成树里的最大值,因为权值很小,所以可以考虑搞一个cnt,一开始pos等于最大边w,接着如果最大边被删掉了,就暴力往下跳pos,直到cnt[pos]>0为止,这样子均摊一下复杂度是O(1)的
代码如下:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 300010
#define M 350010
#define lson ch[x][0]
#define rson ch[x][1]
using namespace std; int cnt[],max1,n,m,ans=0x3f3f3f3f; struct node
{
int from,to,w;
} e[N]; int cmp(node a,node b)
{
return a.w<b.w;
} //lct begin int tag[M],f[M],ch[M][],sum[M]; int not_root(int now)
{
int x=f[now];
return lson==now||rson==now;
} int push_up(int x)
{
sum[x]=x;
if(e[sum[lson]].w>e[sum[x]].w)
{
sum[x]=sum[lson];
}
if(e[sum[rson]].w>e[sum[x]].w)
{
sum[x]=sum[rson];
}
} int rev(int x)
{
swap(lson,rson);
tag[x]^=;
} int push_down(int x)
{
if(tag[x])
{
rev(lson);
rev(rson);
tag[x]^=;
}
} int rotate(int x)
{
int y=f[x],z=f[y],kd=ch[y][]==x,xs=ch[x][!kd];
if(not_root(y))
{
ch[z][ch[z][]==y]=x;
}
ch[x][!kd]=y;
ch[y][kd]=xs;
if(xs) f[xs]=y;
f[y]=x;
f[x]=z;
push_up(y);
} int push_all(int x)
{
if(not_root(x))
{
push_all(f[x]);
}
push_down(x);
} int splay(int x)
{
int y,z;
push_all(x);
while(not_root(x))
{
y=f[x],z=f[y];
if(not_root(y))
{
(ch[y][]==x)^(ch[z][]==y)?rotate(x):rotate(y);
}
rotate(x);
}
push_up(x);
} int access(int x)
{
for(int y=; x; y=x,x=f[x])
{
splay(x);
rson=y;
push_up(x);
}
} int make_root(int x)
{
access(x);
splay(x);
rev(x);
} int split(int x,int y)
{
make_root(x);
access(y);
splay(y);
} int find_root(int x)
{
access(x);
splay(x);
while(lson)
{
push_down(x);
x=lson;
}
return x;
} int link(int x,int y)
{
make_root(x);
if(find_root(y)==x) return ;
f[x]=y;
return ;
} int cut(int x,int y)
{
make_root(x);
if(find_root(y)!=x||f[x]!=y||rson) return ;
f[x]=ch[y][]=;
push_up(y);
return ;
} int print(int x)
{
if(lson) print(lson);
printf("%d ",x);
if(rson) print(rson);
} //lct end //dsu begin int fa[M]; int init()
{
for(int i=; i<M; i++)
{
fa[i]=i;
}
} int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
} int unity(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx==fy) return ;
fa[fx]=fy;
return ;
} //dsu end int main()
{
init();
scanf("%d%d",&n,&m);
for(int i=; i<=m; i++)
{
scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
}
sort(e+,e+m+,cmp);
int tot=;
for(int i=m; i>=; i--)
{
if(e[i].from==e[i].to) continue;
if(unity(e[i].from,e[i].to))
{
tot++;
link(e[i].from+m,i);
link(e[i].to+m,i);
cnt[e[i].w]++;
max1=max(max1,e[i].w);
if(tot==n-) ans=max1-e[i].w;
}
else
{
split(e[i].from+m,e[i].to+m);
int gg=sum[e[i].to+m];
cut(e[gg].to+m,gg);
cut(e[gg].from+m,gg);
cnt[e[gg].w]--;
cnt[e[i].w]++;
while(!cnt[max1])
{
max1--;
}
if(tot==n-) ans=min(ans,max1-e[i].w);
link(e[i].to+m,i);
link(e[i].from+m,i);
}
}
printf("%d\n",ans);
}
洛谷P4234 最小差值生成树(lct动态维护最小生成树)的更多相关文章
- 洛谷 P4234 最小差值生成树(LCT)
题面 luogu 题解 LCT 动态树Link-cut tree(LCT)总结 考虑先按边权排序,从小到大加边 如果构成一颗树了,就更新答案 当加入一条边,会形成环. 贪心地想,我们要最大边权-最小边 ...
- [洛谷P4234] 最小差值生成树
题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:求一棵生成树,其最大边权减最小边权最小 解题思路 和魔法森林非常像.先对所有边进行排序,每次加边的时候删除环上的最小 ...
- 洛谷P4234 最小差值生成树(LCT,生成树)
洛谷题目传送门 和魔法森林有点像,都是动态维护最小生成树(可参考一下Blog的LCT总结相关部分) 至于从小到大还是从大到小当然无所谓啦,我是从小到大排序,每次枚举边,还没连通就连,已连通就替换环上最 ...
- 洛谷.4234.最小差值生成树(LCT)
题目链接 先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差. 每次构成树时更新答案.答案就是当前边减去生成树 ...
- 【刷题】洛谷 P4234 最小差值生成树
题目描述 给定一个标号为从 \(1\) 到 \(n\) 的.有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式: 第一行两个数 \(n, m\) ,表示图的 ...
- P4234 最小差值生成树 LCT维护边权
\(\color{#0066ff}{ 题目描述 }\) 给定一个标号为从 \(1\) 到 \(n\) 的.有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树. \(\color{#0 ...
- 洛谷4234最小差值生成树 (LCT维护生成树)
这也是一道LCT维护生成树的题. 那么我们还是按照套路,先对边进行排序,然后顺次加入. 不过和别的题有所不同的是: 在本题中,我们需要保证LCT中正好有\(n-1\)条边的时候,才能更新\(ans\) ...
- P4234 最小差值生成树
题目 P4234 最小差值生成树 做法 和这题解法差不多,稍微变了一点,还不懂就直接看代码吧 \(update(2019.2):\)还是具体说一下吧,排序,直接加入,到了成环情况下,显然我们要把此边代 ...
- ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」
题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:带权无向图,每条边有权值\(a[i],b[i]\).要求一条从\(1\)到\(N\)的路径,使得这条路径上的\(Ma ...
随机推荐
- C++函数及参数
传值->传递的是数据副本(结构.普通数据类型数据) 传地址->传递的是数据变量的地址(数组等) 传值的缺点是需要复制数据副本,数据量大可能增加内存需求,降低系统运行速度; 传地址也有传地址 ...
- 论XGBOOST科学调参
XGBOOST的威力不用赘述,反正我是离不开它了. 具体XGBOOST的原理可以参见之前的文章<比XGBOOST更快--LightGBM介绍> 今天说下如何调参. bias-varianc ...
- Rhythmk 一步一步学 JAVA(9) JAVA 基础笔记[枚举,...]
1.装箱就是值类型转换为object类型,拆箱相反:object转化为值类型 eg:Integer i=1; // 装箱 int j=i; // 拆箱 2.静态导入: eg: 导入: import s ...
- 跟着太白老师学python day11 可迭代对象和迭代器
如果对象的属性中有__iter__属性就说明是可迭代的,容器类的数据类型都是可迭代对象 如果对象的属性中既有__iter__属性也有__next__属性,就说明这个对象是迭代器 如何判断一个函数是不是 ...
- 好一个Time_Wait状态(TCP/IP)
首先简单介绍一下Time_Wait是个什么鬼: 在TCP/IP协议中,我们都知道有三次握手四次挥手的过程,先来一个简单的图: 各个状态和基本的过程想必了解过TCP/IP协议的人都清楚,本次介绍的主题只 ...
- ubuntu 18.04 - server版 开机启动脚本
ubuntu 18.04 不再使用 inited 管理系统,改用 systemd systemd 默认读取 /etc/systemd/system 下的文件,该目录下的文件会链接/lib/system ...
- LeetCode之数组处理题java
342. Power of Four Total Accepted: 7302 Total Submissions: 21876 Difficulty: Easy Given an integer ( ...
- redis centos7
官网下载tar包 make 修改conf 修改 启动脚本 utils/redis_init_script 开放端口6379
- 【祥哥带你玩HoloLens开发】了解如何实现远程主机为HoloLens实时渲染
今天有一个兄弟在群里讲到他们的项目模型比较大,单用HoloLens运行设备的性能无法满足需要,问道如何将渲染工作交给服务器来做,讲渲染结果传给HoloLens.正好刚刚看官方github的时候发现一个 ...
- Python String模块详解
>>> import string >>> string.ascii_letters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL ...