题目链接

先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差。

每次构成树时更新答案。答案就是当前边减去生成树上最小边的权值。

LCT上维护最小边的编号。求最小边把树上的边用vis[]标记即可。

不熟啊.

(另外暴力可以排序后枚举一个分界点,在它之后求最小生成树,在它之前求最大生成树)

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define INF 10000007
const int N=5e4+5,M=2e5+5,S=N+M; int n,m,_fa[N];
bool vis[M];
struct Edge
{
int fr,to,val;
Edge() {}
Edge(int f,int t,int v): fr(f),to(t),val(v) {}
bool operator <(const Edge &a)const {
return val<a.val;
}
}e[M];
namespace LCT
{
#define lson son[x][0]
#define rson son[x][1] int fa[S],son[S][2],sk[S],pos[S],val[S];
bool tag[S];
inline int Get(int x,int y){//取最小的边
return val[x]<val[y]?x:y;
}
inline void Update(int x){
pos[x]=Get(x,Get(pos[lson],pos[rson]));//是左右儿子的最小边pos[]!
}
inline bool n_root(int x){
return son[fa[x]][0]==x||son[fa[x]][1]==x;
}
inline void Rev(int x){
std::swap(lson,rson), tag[x]^=1;
}
void PushDown(int x){
if(tag[x]) Rev(lson),Rev(rson),tag[x]=0;
}
void Rotate(int x)
{
int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
if(n_root(a)) son[b][son[b][1]==a]=x;
if(son[x][r]) fa[son[x][r]]=a;
fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
Update(a);
}
void Splay(int x)
{
int t=1,a=x; sk[1]=x;
while(n_root(a)) sk[++t]=a=fa[a];
while(t) PushDown(sk[t--]);
while(n_root(x))
{
if(n_root(a=fa[x])) Rotate(son[a][1]==x^son[fa[a]][1]==a?x:a);
Rotate(x);
}
Update(x);
}
void Access(int x){
for(int pre=0; x; x=fa[pre=x])
Splay(x), rson=pre, Update(x);
}
void Make_root(int x){
Access(x), Splay(x), Rev(x);
}
void Split(int x,int y){
Make_root(x), Access(y), Splay(y);
}
void Link(int x){
Make_root(e[x].to), fa[fa[e[x].to]=x+N]=e[x].fr;
}
void Cut(int x){
Access(e[x-N].to), Splay(x), lson=rson=fa[lson]=fa[rson]/*=fa[x]*/=0;//fa[x]应该是用不到吧。。注意更新顺序!后更新lson,rson...
}
}
using namespace LCT; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Get_fa(int x){
return x==_fa[x]?x:_fa[x]=Get_fa(_fa[x]);
} int main()
{
n=read(),m=read();
val[0]=INF;//空节点!
for(int i=1; i<=n; ++i) _fa[i]=i, val[i]=INF;//点有自己的权值,设为INF避免影响答案(最小边)
for(int u,v,w,i=1; i<=m; ++i) u=read(),v=read(),w=read(),e[i]=Edge(u,v,w);
std::sort(e+1,e+1+m);
// for(int i=1; i<=m; ++i) val[i+N]=e[i].val;
int res=1e6;
for(int p=1,x,y,k=1,i=1; i<=m; ++i)
{
val[i+N]=e[i].val, x=e[i].fr, y=e[i].to;
if(k<n && Get_fa(x)!=Get_fa(y))
{
_fa[_fa[x]]=_fa[y];//路径压缩后
Link(i), vis[i]=1;
if(++k>=n) res=e[i].val-e[p].val;
}
else if(x!=y)//不要计算重边
{
Split(x,y);
vis[pos[y]-N]=0, vis[i]=1;//别忘了Splay(y)后再用y的信息pos[y]!而且要先用pos[y]清vis再Cut().
while(!vis[p]) ++p;
Cut(pos[y]), Link(i);
if(k>=n) res=std::min(res,e[i].val-e[p].val);
}
}
printf("%d",res); return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

  7. Luogu 4234 最小差值生成树 - LCT 维护链信息

    Solution 将边从小到大排序, 添新边$(u, v)$时 若$u,v$不连通则直接添, 若连通则 把链上最小的边去掉 再添边. 若已经加入了 $N - 1$条边则更新答案. Code #incl ...

  8. luogu 4234 最小差值生成树 LCT

    感觉码力严重下降~ #include <bits/stdc++.h> #define N 400006 #define inf 1000000000 #define setIO(s) fr ...

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

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

随机推荐

  1. A1pass大大对黑客学习的建议

    本文转自:http://bbs.hackav.com/thread-92-1-1.html 菜鸟不可怕,可怕的是你认为自己一辈子都是菜鸟.每个高手都是从菜鸟进化过来的,就算是现在黑客界的泰斗们当年也无 ...

  2. weblogic实时监控开发

    参考api文档 https://docs.oracle.com/cd/E13222_01/wls/docs90/wlsmbeanref/core/index.html https://docs.ora ...

  3. VMware如何给虚拟机添加新硬盘

    在使用虚拟机时,若硬盘空间不足.或需要用到双硬盘或多硬盘环境时,我们可以给虚拟机新增虚拟硬盘

  4. 深入解析内存原理:SRAM的基本原理

    1. SRAM芯片的引脚定义早期的SRAM 芯片采用了20 线双列直插(DIP:Dual Inline Package)封装技术,它们之所以具有这么多的针脚,是因为它们必须:• 每个地址信号都需要一根 ...

  5. 018_nginx_proxy死循环问题

    今天线上遇到一个请求一次,触发多次的请求,而且直接把nginx机器压垮了.经排查,经过如下: 一. server{ server www.jyall.com; location /latestrele ...

  6. centos6下的lvm逻辑卷的管理

    LVM:Logical Volume Manager 将多块设备组合成一个来使用 dm:device mapper 设备映射 设备文件 /dev/卷组名/逻辑卷名          /dev/mapp ...

  7. 解决Android SDK下载和更新失败问题

    今天更新sdk报错如下: Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-1.xml. 说dl- ...

  8. GO-time.after 用法

    初学GO,time包里sleep是最常用,今天突然看到一个time.after,特记录time.after用法笔记如下: 首先是time包里的定义 // After waits for the dur ...

  9. VM 安装 linux Enterprise_R5_U4_Server_I386_DVD教程图解

    ocp 学习笔记 20161126--------linux 笔记整理 一:安装linux系统环境: 1:linux 系统安装包下载路径:链接:链接: https://pan.baidu.com/s/ ...

  10. JavaScript中的事件冒泡?事件传播的解释

    注:本文来源  可译网 事件冒泡是你在学习javaScript旅途中遇到的一个术语,它涉及到当一个元素被另一个元素嵌套时调用事件处理的顺序,并且两个元素注册了同一个事件(例如,点击事件). 但是事件冒 ...