博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4234 最小差值生成树
阅读量:4952 次
发布时间:2019-06-11

本文共 3700 字,大约阅读时间需要 12 分钟。

LCT维护生成树

把边从小到大排序,然后一条一条加边,如果成环就把环上最小的删了,我们得到的第一个生成树就是最小生成树。

然后之后每一条边都比前面的生成树的最大边大,我们用这条边的权值减去生成树里最小的,更新答案即可。

因为要维护的是最小值,用排序之后的性质,下表小的值更小来pushup

#include 
#define INF 0x3f3f3f3f#define full(a, b) memset(a, b, sizeof a)#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)using namespace std;typedef long long LL;inline int lowbit(int x){ return x & (-x); }inline int read(){ int ret = 0, w = 0; char ch = 0; while(!isdigit(ch)){ w |= ch == '-', ch = getchar(); } while(isdigit(ch)){ ret = (ret << 3) + (ret << 1) + (ch ^ 48); ch = getchar(); } return w ? -ret : ret;}inline int lcm(int a, int b){ return a / __gcd(a, b) * b; }template
inline A fpow(A x, B p, C lyd){ A ans = 1; for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd; return ans;}const int N = 500005;int n, m, cnt, tot, cur, ans, val[N], fa[N], ch[N][2], rev[N], id[N], st[N];bool vis[N];struct Edge { int u, v, w; bool operator < (const Edge &rhs) const { return w < rhs.w; }} e[N];int newNode(int x){ ++ tot; val[tot] = x, id[tot] = tot; rev[tot] = ch[tot][0] = ch[tot][1] = fa[tot] = 0; return tot;}bool isRoot(int x){ return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}void reverse(int x){ rev[x] ^= 1, swap(ch[x][0], ch[x][1]);}void push_up(int x){ id[x] = x; int l = ch[x][0], r = ch[x][1]; if(id[l] > n && (id[x] <= n || id[x] > id[l])) id[x] = id[l]; if(id[r] > n && (id[x] <= n || id[x] > id[r])) id[x] = id[r];}void push_down(int x){ if(rev[x]){ int l = ch[x][0], r = ch[x][1]; if(l) reverse(l); if(r) reverse(r); rev[x] ^= 1; }}void rotate(int x){ int y = fa[x], z = fa[y], p = (ch[y][1] == x) ^ 1; ch[y][p^1] = ch[x][p], fa[ch[x][p]] = y; if(!isRoot(y)) ch[z][ch[z][1] == y] = x; fa[x] = z, fa[y] = x, ch[x][p] = y; push_up(y), push_up(x);}void splay(int x){ int pos = 0; st[++pos] = x; for(int i = x; !isRoot(i); i = fa[i]) st[++pos] = fa[i]; while(pos) push_down(st[pos--]); while(!isRoot(x)){ int y = fa[x], z = fa[y]; if(!isRoot(y)){ (ch[y][0] == x) ^ (ch[z][0] == y) ? rotate(x) : rotate(y); } rotate(x); } push_up(x);}void access(int x){ for(int p = 0; x; p = x, x = fa[x]){ splay(x), ch[x][1] = p, push_up(x); }}void makeRoot(int x){ access(x), splay(x), reverse(x);}void link(int x, int y){ makeRoot(x); fa[x] = y;}int findRoot(int x){ access(x), splay(x); while(ch[x][0]) push_down(x), x = ch[x][0]; splay(x); return x;}void split(int x, int y){ makeRoot(x), access(y), splay(y);}bool isConnect(int x, int y){ makeRoot(x); return findRoot(y) == x;}int main(){ n = read(), m = read(); for(int i = 1; i <= m; i ++){ e[i].u = read(), e[i].v = read(), e[i].w = read(); } ans = INF, cur = 1; sort(e + 1, e + m + 1); for(int i = 1; i <= n; i ++) newNode(0); for(int i = 1; i <= m; i ++) newNode(e[i].w); for(int i = 1; i <= m; i ++){ int u = e[i].u, v = e[i].v, w = e[i].w; if(u == v) continue; if(!isConnect(u, v)){ link(u, i + n), link(i + n, v); vis[i] = true, cnt ++; } else{ split(u, v); int tmp = id[v]; splay(tmp); fa[ch[tmp][0]] = fa[ch[tmp][1]] = 0; ch[tmp][0] = ch[tmp][1] = 0; vis[tmp - n] = false, vis[i] = true; link(u, i + n), link(i + n, v); while(!vis[cur]) cur ++; } if(cnt == n - 1) ans = min(ans, w - e[cur].w); } cout << ans << endl; return 0;}

转载于:https://www.cnblogs.com/onionQAQ/p/11232377.html

你可能感兴趣的文章
第四次 博客作业
查看>>
pymysql 读取数据库没有字段
查看>>
【nginx】关于gzip压缩
查看>>
Spring Boot 邮件发送的 5 种姿势!
查看>>
ZOJ.3551.Bloodsucker(期望DP)
查看>>
BZOJ.3261.最大异或和(可持久化Trie)
查看>>
IMU数据积分获得当前位姿
查看>>
logging 日志模块 configparser 配置文件
查看>>
广播接收者案例_开机启动
查看>>
Swift版iOS游戏框架Sprite Kit基础教程下册
查看>>
Android 整合实现简单易用、功能强大的RecyclerView
查看>>
(转)25个必须记住的SSH命令
查看>>
禁用并删除 Wordpress 文章修订(revision)记录
查看>>
shell 函数
查看>>
layer iframe层的使用,传参
查看>>
Cocoapods
查看>>
[No0000C7]windows 10桌面切换快捷键,win10
查看>>
统一修改表单参数(表单提交的空字符串统一转null)
查看>>
《程序员修炼之道:从小工到专家》拔萃簿
查看>>
学习和推断
查看>>