洛谷 P4234 LCT + 排序 + 枚举

news/2024/11/21 1:35:37/

       求边权最大值与最小值的差值最小的生成树,输出这个差值大小。

       按权值排序,我们等同于枚举最大值,然后更新生成树让生成树的最小值尽可能最大。

       也就是每次加入边,若构成环,则去掉环上最小值。

       若加入边不会构成环,则此时的差值 g a p gap gap,一定是最优的 g a p gap gap

       若加入当前最大值的边会构成环,则去掉环上最小值后,更新当前的生成树中的值。重新计算 g a p gap gap,只有 g a p gap gap 更小的时候,才更新 b e s t g a p bestgap bestgap

       几个小细节:

       1.由于我们要维护最小值,所以需要初始化为无穷大 i n f inf inf

       2.由于该题联通性不会变小(就是即使有 c u t cut cut 操作,也不会使得两个点失去联通性),所以可以使用并查集来判断是否成环,可以比 L C T LCT LCT 的换根再判断是否根相同节约时间。

       3.倒过来的操作也是同理的,比如枚举最小值,更新最大值。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
#define Ri register int
typedef long long LL;
const int maxn = 3e5 + 5;
const int inf = 1e9;struct node{int fa, son[2], val, res, id;   //  res is the xor resultbool tag;                   //  reverse lazy tag
}spl[maxn];#define ls(x) (spl[x].son[0])
#define rs(x) (spl[x].son[1])
#define fa(x) (spl[x].fa)
#define ident(x, fa) (rs(fa) == x)
#define connect(x, f, no) (spl[fa(x) = f].son[no] = x)
#define ntroot(x) (ls(fa(x)) == x || rs(fa(x)) == x)        // not the root of splay
#define reverse(x) swap(ls(x), rs(x)), spl[x].tag ^= true
inline void update(Ri x){Ri l = ls(x), r = rs(x);spl[x].res = spl[x].val;spl[x].id = x;if(spl[x].res > spl[l].res){spl[x].res = spl[l].res;spl[x].id = spl[l].id;}if(spl[x].res > spl[r].res){spl[x].res = spl[r].res;spl[x].id = spl[r].id;}
}inline void pushdown(Ri x){if(spl[x].tag){if(ls(x)) reverse(ls(x));if(rs(x)) reverse(rs(x));spl[x].tag = false;}
}inline void pushall(Ri x){if(ntroot(x)) pushall(fa(x));pushdown(x);
}inline void rotate(Ri x){Ri fa = fa(x), gf = fa(fa), k = ident(x, fa);connect(spl[x].son[k ^ 1], fa, k);fa(x) = gf;if(ntroot(fa)) spl[gf].son[ident(fa, gf)] = x;connect(fa, x, k ^ 1);update(fa), update(x);
}inline void splaying(Ri x){            // to the rootpushall(x);                         // push lazy tagwhile(ntroot(x)){int fa = fa(x), gf = fa(fa);if(ntroot(fa)) ident(fa, gf) ^ ident(x, fa) ? rotate(x) : rotate(fa);rotate(x);}
}inline void access(Ri x){              // link x to the rootfor(Ri y = 0; x; x = fa(y = x)){splaying(x);rs(x) = y;                      // link right son to the root of last splayupdate(x);}
}inline void mkroot(Ri x){              // trans the rootaccess(x);                          // link, and x will the right-most of the splay (the most dep)splaying(x);                        // after splaying, x will not have right sonreverse(x);                         // reverse the dep index
}inline int findroot(Ri x){             // find the root of splayaccess(x);splaying(x);while(ls(x)){pushdown(x);x = ls(x);}splaying(x);                        // prevent link too longreturn x;
}inline void link(Ri x, Ri y){mkroot(x);if(findroot(y) == x) return;        // x and y are in the same splay, not legalfa(x) = y;
}inline void cut(Ri x, Ri y){mkroot(x);if(findroot(y) != x || fa(y) != x || ls(y)) return; // not legalfa(y) = rs(x) = 0;update(x);
}inline void split(Ri x, Ri y){        // split the road x to ymkroot(x);access(y);splaying(y);// now y have no right son, and the left son is a road to the x// and the res of y is the res of the road x to y
}//---------------------------------
pair<int, int> his[maxn];
int edge, fa[maxn];
int gap, bestgap;
struct ooo{int u, v, c;inline bool operator <(const ooo&x) const &{return c < x.c;}
}all[maxn];multiset<int> minnum;inline int getroot(Ri x){return x == fa[x] ? x : fa[x] = getroot(fa[x]);
}inline void link1(const ooo &al){edge++;spl[edge].val = spl[edge].res = al.c;spl[edge].id = edge;his[edge].first = al.u;his[edge].second = al.v;link(al.u, edge);link(edge, al.v);minnum.insert(al.c);gap = *minnum.rbegin() - *minnum.begin();
}inline void link2(const ooo &al){split(al.u, al.v);Ri b = spl[al.v].id, c = spl[al.v].res;minnum.erase(minnum.find(c));cut(his[b].first, b);cut(b, his[b].second);link1(al);
}int main(){//IOS;Ri n, m, x, y;cin >> n >> m;edge = n;for(Ri i = 0; i <= n; i++){spl[i].res = spl[i].val = inf;fa[i] = i;}for(Ri i = 1; i <= m; i++)cin >> all[i].u >> all[i].v >> all[i].c;sort(all + 1, all + 1 + m);for(Ri i = 1; i <= m; i++){if(getroot(x = all[i].u) == getroot(y = all[i].v)){if(x == y) continue;link2(all[i]);if(gap < bestgap)bestgap = gap;}else{fa[fa[x]] = fa[y];link1(all[i]);bestgap = gap;}}cout << bestgap << endl;
}

http://www.ppmy.cn/news/356262.html

相关文章

LuoguP4234_最小差值生成树_LCT

LuoguP4234_最小差值生成树_LCT 题意&#xff1a; 给出一个无向图&#xff0c;求最大的边权减最小的边权最小的一棵生成树。 分析&#xff1a; 可以把边权从大到小排序&#xff0c;然后类似魔法森林那样插入。 如果两点不连通&#xff0c;直接连上&#xff0c;否则找到两点间最…

NKOJ 4234 三角分形

问题描述 今天何老板得到了一个神奇的正三角形&#xff0c;它具有自动分形技能。 一天后&#xff0c;它会分成4个相同的正三角形&#xff0c;其中三个“尖尖”朝上&#xff0c;一个“尖尖”朝下。 一天后&#xff0c;里面的每个三角形又会按上述规则分形下去。 如此反复………

[luogu4234]最小差值生成树

[luogu4234]最小差值生成树 luogu 从小到大枚举边,并连接,如果已连通就删掉路径上最小边 lct维护\(ansmin(E_{max}-E_{min})\) #include<bits/stdc.h> using namespace std; const int _4e55; int re(){int x0,w1;char chgetchar();while(ch<0||ch>9){if(ch-)w-1;c…

HDU 4234 Moving Points

刚开始做的时候还以为是暴搜&#xff0c;YY了各种剪枝&#xff0c;结果华丽丽的TLE了 正解&#xff1a; 状态压缩DP dp[当前走到的点][状态] 状态&#xff1a; 第i位表示第i个点有没有被消灭 转移&#xff1a; 详见代码 注意&#xff1a; 计算转移cost时要用O(1) 的算法 二分…

4234最小差值生成树

有点巧妙啊&#xff01; s[x]每次维护的是最小值 我们将边按从大到小排个序,这样编号小的就在前面啦&#xff01;QAQ 再按最小生成树的LCT的做法来 不过我们每次要用一个book标记前面最小边的编号 每次要更新答案时&#xff0c;一直往前跳&#xff0c;跳到最晚更新的即使最小的…

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

题目链接 先将边排序&#xff0c;这样就可以按从小到大的顺序维护生成树&#xff0c;枚举到一条未连通的边就连上&#xff0c;已连通则(用当前更大的)替换掉路径上最小的边&#xff0c;这样一定不会更差。 每次构成树时更新答案。答案就是当前边减去生成树上最小边的权值。 LCT…

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

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

洛谷P4234 最小差值生成树 题解

洛谷P4234 最小差值生成树 题解 题目链接&#xff1a;P4234 最小差值生成树 题意&#xff1a;给定一个点标号从 1 1 1 到 n n n 的、有 m m m 条边的无向图&#xff0c;求边权最大值与最小值的差值最小的生成树&#xff0c;图可能存在自环 这个题不太好利用kruskal来维护&a…