Description
给定一张n个点,m条边的无向图,求出边权最大值和最小值差值最小的生成树
Solution
LCT+并查集
按照最小生成树的思路,先将边按照边权从小到大排序,然后顺序考虑每一条边
如果当前这条边的两个端点没有连通,那么直接连通
如果两个端点已经连通,我们加上这条边会形成一个环,那么为了让“边权最大值和最小值差值”尽可能小,我们可以将这个环上最短的一条边删掉,换成这条边(显然是对的)
维护最小值可以通过LCT实现,连边、短边也是LCT的基本操作
当目前的边已经是一棵树的时候更新答案即可完成
Code

1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int N = 50010;
5 const int M = 200010;
6 inline int read() {
7 int ret = 0, op = 1;
8 char c = getchar();
9 while (!isdigit(c)) {
10 if (c == '-') op = -1;
11 c = getchar();
12 }
13 while (isdigit(c)) {
14 ret = (ret << 3) + (ret << 1) + c - '0';
15 c = getchar();
16 }
17 return ret * op;
18 }
19 struct Edge {
20 int from, to, dis;
21 bool operator <(const Edge &x) const {
22 return dis < x.dis;
23 }
24 } edge[M];
25 struct LCT {
26 int fa, val, minn, ch[2], tag;
27 } a[N + M];
28 int n, m, s[N + M], f[N];
29 int vis[M];
30 int find(int x) {
31 if (f[x] != x) return f[x] = find(f[x]);
32 return f[x];
33 }
34 inline int isnroot(int now) {
35 return a[a[now].fa].ch[0] == now || a[a[now].fa].ch[1] == now;
36 }
37 inline int get(int x, int y) {
38 return a[x].val < a[y].val ? x : y;
39 }
40 inline void update(int now) {
41 int l = a[now].ch[0];
42 int r = a[now].ch[1];
43 a[now].minn = get(now, get(a[l].minn, a[r].minn));
44 }
45 inline void rev(int now) {
46 swap(a[now].ch[0], a[now].ch[1]);
47 a[now].tag ^= 1;
48 }
49 inline void pushdown(int now) {
50 if (a[now].tag) {
51 if (a[now].ch[0]) rev(a[now].ch[0]);
52 if (a[now].ch[1]) rev(a[now].ch[1]);
53 a[now].tag = 0;
54 }
55 }
56 void rotate(int x) {
57 int y = a[x].fa;
58 int z = a[y].fa;
59 int xson = a[y].ch[1] == x;
60 int yson = a[z].ch[1] == y;
61 int B = a[x].ch[xson ^ 1];
62 if (isnroot(y)) a[z].ch[yson] = x;
63 a[x].ch[xson ^ 1] = y;
64 a[y].ch[xson] = B;
65 if (B) a[B].fa = y;
66 a[y].fa = x;
67 a[x].fa = z;
68 update(y);
69 }
70 void splay(int x) {
71 int y = x, z = 0;
72 s[++z] = y;
73 while (isnroot(y)) y = a[y].fa, s[++z] = y;
74 while (z) pushdown(s[z--]);
75 while (isnroot(x)) {
76 y = a[x].fa;
77 z = a[y].fa;
78 if (isnroot(y))
79 (a[z].ch[0] == y) ^ (a[y].ch[0] == x) ? rotate(x) : rotate(y);
80 rotate(x);
81 }
82 update(x);
83 }
84 void access(int x) {
85 for (register int y = 0; x; y = x, x = a[x].fa) {
86 splay(x); a[x].ch[1] = y; update(x);
87 }
88 }
89 void makeroot(int x) {
90 access(x);
91 splay(x);
92 rev(x);
93 }
94 void link(int i) {
95 makeroot(edge[i].from);
96 a[edge[i].from].fa = i + N;
97 a[i + N].fa = edge[i].to;
98 }
99 void cut(int i) {
100 access(edge[i - N].from);
101 splay(i);
102 a[a[i].ch[1]].fa = a[a[i].ch[0]].fa = 0;
103 a[i].ch[0] = a[i].ch[1] = 0;
104 }
105 int main() {
106 n = read(); m = read();
107 for (register int i = 0; i <= n; ++i) f[i] = i, a[i].val = 2147483647;
108 for (register int i = 1; i <= m; ++i) {
109 edge[i].from = read(); edge[i].to = read(); edge[i].dis = read();
110 }
111 sort(edge + 1, edge + m + 1);
112 int sum = 0, ans = 0, k = 1;
113 for (register int i = 1; i <= m; ++i) {
114 a[i + N].val = edge[i].dis;
115 int x = edge[i].from;
116 int y = edge[i].to;
117 if (find(x) != find(y)) {
118 vis[i] = 1;
119 sum++;
120 link(i);
121 f[f[x]] = f[y];
122 if (sum == n - 1) ans = edge[i].dis - edge[k].dis;
123 }
124 else {
125 if (x == y) continue ;
126 vis[i] = 1;
127 makeroot(x);
128 access(y); splay(y);
129 vis[a[y].minn - N] = 0;
130 while (vis[k] == 0) ++k;
131 cut(a[y].minn); link(i);
132 if (sum == n - 1) ans = min(ans, edge[i].dis - edge[k].dis);
133 }
134 }
135 printf("%d\n", ans);
136 return 0;
137 }
