P4234 最小差值生成树 LCT维护边权
\(\color{#0066ff}{ 题目描述 }\)
给定一个标号为从 \(1\) 到 \(n\) 的、有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树。
\(\color{#0066ff}{输入格式}\)
第一行两个数 \(n, m\),表示图的点和边的数量。
第二行起 mm 行,每行形如 u_i, v_i, w_iui,vi,wi,代表 u_iui 到 v_ivi 间有一条长为 w_iwi 的无向边。
\(\color{#0066ff}{输出格式}\)
输出一行一个整数,代表你的答案。
数据保证存在至少一棵生成树。
\(\color{#0066ff}{输入样例}\)
4 6
1 2 10
1 3 100
1 4 90
2 3 20
2 4 80
3 4 40
\(\color{#0066ff}{输出样例}\)
20
\(\color{#0066ff}{数据范围与提示}\)
对于 30% 的数据,满足 \(1 \leq n \leq 100, 1 \leq m \leq 1000\)
对于 97% 的数据,满足 \(1 \leq n \leq 500, 1 \leq m \leq 100000\)
对于 100% 的数据,满足 \(1 \leq n \leq 50000, 1 \leq m \leq 200000, 1 \leq w_i \leq 10000\)
\(\color{#0066ff}{题解}\)
把所有边从大到小排个序,依次加入LCT,LCT上维护边权(拆成点)
如果不成环,直接加入边,用一个变量维护LCT上的边数
如果成环了,那么显然把最大的换下来更优
用multiset维护最大最小值,每次只要是生成树就更新
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 5e5 + 10;
const int inf = 0x7fffffff;
struct node {
node *ch[2], *fa;
int max, val, rev;
node(int max = 0, int val = 0, int rev = 0): max(max), val(val), rev(rev) { ch[0] = ch[1] = fa = NULL; }
void trn() { std::swap(ch[0], ch[1]), rev ^= 1; }
void dwn() {
if(!rev) return;
if(ch[0]) ch[0]->trn();
if(ch[1]) ch[1]->trn();
rev = 0;
}
void upd() {
max = val;
if(ch[0]) max = std::max(max, ch[0]->max);
if(ch[1]) max = std::max(max, ch[1]->max);
}
bool ntr() { return fa && (fa->ch[0] == this || fa->ch[1] == this); }
bool isr() { return fa->ch[1] == this; }
void clr() {
if(ch[0]) ch[0]->fa = NULL;
if(ch[1]) ch[1]->fa = NULL;
ch[0] = ch[1] = NULL;
}
}pool[maxn];
struct EDGE {
int x, y, z;
friend bool operator < (const EDGE &a, const EDGE &b) { return a.z > b.z; }
}e[maxn];
int ans = inf, num;
std::multiset<int> s;
int n, m;
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(y->ntr()) z->ch[y->isr()] = x;
(x->ch[!k] = y)->ch[k] = w;
(y->fa = x)->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
static node *st[maxn];
int top;
st[top = 1] = o;
while(st[top]->ntr()) st[top + 1] = st[top]->fa, top++;
while(top) st[top--]->dwn();
while(o->ntr()) {
if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
node *find(node *o) {
while(o->dwn(), o->max != o->val) {
if(o->ch[0] && o->ch[0]->max == o->max) o = o->ch[0];
else o = o->ch[1];
}
return o;
}
void access(node *x) {
for(node *y = NULL; x; x = (y = x)->fa)
splay(x), x->ch[1] = y, x->upd();
}
void makeroot(node *x) { access(x), splay(x), x->trn(); }
node *findroot(node *o) {
access(o), splay(o);
while(o->dwn(), o->ch[0]) o = o->ch[0];
return o;
}
void link(node *x, node *y) { makeroot(x), x->fa = y; }
void add(node *x, node *y, node *o) {
if(findroot(x) == findroot(y)) {
makeroot(x), access(y), splay(y);
num--;
node *p = find(y);
s.erase(s.find(p->max));
splay(p);
p->clr(), p->upd();
}
num++;
s.insert(o->val);
if(num == n - 1 && num) {
std::multiset<int>::iterator be = s.begin(), ed = s.end();
ed--;
ans = std::min(ans, *ed - *be);
}
link(x, o), link(y, o);
}
int main() {
n = in(), m = in();
for(int i = 1; i <= m; i++) e[i].x = in(), e[i].y = in(), e[i].z = in();
std::sort(e + 1, e + m + 1);
for(int i = 1; i <= m; i++) {
if(e[i].x == e[i].y) continue;
pool[n + i].val = e[i].z;
pool[n + i].upd();
add(pool + e[i].x, pool + e[i].y, pool + n + i);
}
printf("%d", ans);
return 0;
}
P4234 最小差值生成树 LCT维护边权的更多相关文章
- 洛谷 P4234 最小差值生成树(LCT)
题面 luogu 题解 LCT 动态树Link-cut tree(LCT)总结 考虑先按边权排序,从小到大加边 如果构成一颗树了,就更新答案 当加入一条边,会形成环. 贪心地想,我们要最大边权-最小边 ...
- Luogu 4234 最小差值生成树 - LCT 维护链信息
Solution 将边从小到大排序, 添新边$(u, v)$时 若$u,v$不连通则直接添, 若连通则 把链上最小的边去掉 再添边. 若已经加入了 $N - 1$条边则更新答案. Code #incl ...
- P4234 最小差值生成树
题目 P4234 最小差值生成树 做法 和这题解法差不多,稍微变了一点,还不懂就直接看代码吧 \(update(2019.2):\)还是具体说一下吧,排序,直接加入,到了成环情况下,显然我们要把此边代 ...
- 洛谷.4234.最小差值生成树(LCT)
题目链接 先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差. 每次构成树时更新答案.答案就是当前边减去生成树 ...
- 洛谷P4234 最小差值生成树(lct动态维护最小生成树)
题目描述 给定一个标号为从 11 到 nn 的.有 mm 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式: 第一行两个数 n, mn,m ,表示图的点和边的数量. ...
- 【Luogu】P4234最小差值生成树(LCT)
题目链接 能把LCT打得每个函数都恰有一个错误也是挺令我惊讶的. 本题使用LCT维护生成树,具体做法是对原图中的每个边建一个点,然后连边的时候相当于是将边的起点跟“边”这个点连起来,边的终点也跟它连起 ...
- 洛谷P4234 最小差值生成树(LCT,生成树)
洛谷题目传送门 和魔法森林有点像,都是动态维护最小生成树(可参考一下Blog的LCT总结相关部分) 至于从小到大还是从大到小当然无所谓啦,我是从小到大排序,每次枚举边,还没连通就连,已连通就替换环上最 ...
- 【刷题】洛谷 P4234 最小差值生成树
题目描述 给定一个标号为从 \(1\) 到 \(n\) 的.有 \(m\) 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式: 第一行两个数 \(n, m\) ,表示图的 ...
- Luogu P4234 最小差值生成树
题意 给定一个 \(n\) 个点 \(m\) 条边的有权无向图,求出原图的一棵生成树使得该树上最大边权与最小边权的差值最小. \(\texttt{Data Range:}1\leq n\leq 5\t ...
随机推荐
- 分布式代码管理github
Git是世界上最先进的分布式版本的控制系统,特点是:简单大气上档次. Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了.
- CPU, PSU, SPU的区别
It all started in January 2005 with Critical Patch Updates (CPU). Then Patch Set Updates (PSU) were ...
- nginx upstream的几种配置方式
nginx 的upstream目前支持4种方式的分配 1.轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器 ,如果后端服务器down掉,能自动剔除. 2.weight指定轮询几率,weigh ...
- Shell编程进阶 1.8 for循环
产生序列的命令 seq 1 2 3 4 5 6 7 8 9 10 seq 1 3 5 7 9 (从1开始增加2显示这个数字,到10结束) seq - 10 8 6 4 2 seq - 10 9 8 ...
- LAMP 2.8 php.ini配置文件详解
修改php配置文件,但有时候我们并不知道 php.ini 所在路径,这时候就需要通过命令来查一查在哪里. /usr/local/php/bin/php -i |head 看那一行 Loaded Con ...
- myeclipse 10破解
因为笔者的电脑是刚买不久,忘记先给电脑分区,等软年安装差不多了才发现忘记分区,所以就备份了数据,然后分区,结果分区过程中没有异常发生,就没用备用数据,就用分过区的原数据,当时还以为没问题,结果打开my ...
- java判断一个字符串中是否包含全角
public static boolean isAngle(String str){ if(str.getBytes().length==str.length()){ //全是半角 return tr ...
- python中的变量以及字符串的使用
在python中只有一个变量:动态变量 在Python当中令人奇怪的是我们的python没有静态变量,这个特性大大的增加了python的灵活性. 由于python中没有静态变量所以我们千万不要使用静态 ...
- 《Android应用性能优化》 第4章 高效使用内存
本地类型 大小 字节 boolean jboolean 8位(取决于VM) 1 byte jbyte 8位 1 char jchar 16位 2 short jshort 16位 2 int ji ...
- C++面向对象类的实例题目三
编写一个程序,设计一个满足如下要求的CData类. (1)用下面的格式输出日期:日/月/年 (2)输出在当前日期上加一天后的日期 (3)设置日期 code: #include<iostream& ...