洛谷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 ...
随机推荐
- 超简单让ubuntu开启wifi热点(亲测16.04与14.04可用)
今天教大家一个简单方法让ubuntu发散wifi热点给手机或者其他设备使用. 首先,创建一个普通的热点,点击右上角的网络,然后选择下拉菜单中的编辑连接,然后出现以下界面. 然后点击增加,连接类型选接W ...
- Java知识总结----队列的使用
首先我们要知道使用队列的目的是什么?一般情况下,如果是一些及时消息的处理,并且处理时间很短的情况下是不需要使用队列的,直接阻塞式的方法调用就可以了.但是,如果在消息处理的时候特别费时间,这个时候如果有 ...
- C#做的在线升级小程序
转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...
- C# 泛型编程之泛型类、泛型方法、泛型约束
来自Hauk的文章 C# 泛型编程之泛型类.泛型方法.泛型约束 所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型. 泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为 ...
- A标签的href设置为#代表什么意思?
空锚点<a href="#abc">a link <#>表示跳到锚点abc,<a href="#">a link <# ...
- angular的service与factory
angular里的service是一个单例对象,在应用生命周期结束的时候(关闭浏览器)才会被清除.而controllers在不需要的时候就会被销毁了. factory是angular里的一种ser ...
- href 和src 的区别
转载地址:http://www.58maisui.com/2016/08/03/30/?utm_source=tuicool&utm_medium=referral href和src的区别: ...
- 微服务性能优化之thrift改造
在我当前所做的web项目中,采用前后端分离模式前端通过Django 提供restful接口,后端采用微服务架构,微服务之间的调用采用jsonrpc,由于微服务之间的调用很频繁,导致前端得到的响应很慢, ...
- Apache Hive (六)Hive SQL之数据类型和存储格式
转自:https://www.cnblogs.com/qingyunzong/p/8733924.html 一.数据类型 1.基本数据类型 Hive 支持关系型数据中大多数基本数据类型 类型 描述 示 ...
- solr的客户端操作:使用solrj进行curd操作
导入相关的jar包 <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-s ...