Luogu 4234 最小差值生成树 - LCT 维护链信息
Solution
将边从小到大排序, 添新边$(u, v)$时 若$u,v$不连通则直接添, 若连通则 把链上最小的边去掉 再添边。
若已经加入了 $N - 1$条边则更新答案。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 using namespace std; 6 7 const int N = 1e5 + 5; 8 const int inf = 1e9; 9 10 int n, m, ans = inf; 11 int vis[N << 2]; 12 13 struct edge { 14 int u, v, w; 15 }e[N << 1]; 16 17 int cmp(const edge &A, const edge &B) { 18 return A.w < B.w; 19 } 20 21 int read() { 22 int X = 0, p = 1; char c = getchar(); 23 for (; c > '9' || c < '0'; c = getchar()) 24 if (c == '-') p = -1; 25 for (; c >= '0' && c <= '9'; c = getchar()) 26 X = X * 10 + c - '0'; 27 return X * p; 28 } 29 30 void cmin(int &A, int B) { 31 if (A > B) 32 A = B; 33 } 34 35 namespace LCT { 36 int val[N << 2], ch[N << 2][2], f[N << 2], mx[N << 2], tun[N << 2]; 37 #define lc(x) ch[x][0] 38 #define rc(x) ch[x][1] 39 40 int isroot(int x) { 41 return lc(f[x]) != x && rc(f[x]) != x; 42 } 43 44 int get(int x) { 45 return rc(f[x]) == x; 46 } 47 48 void up(int x) { 49 mx[x] = val[x]; 50 if (e[mx[lc(x)]].w < e[mx[x]].w) mx[x] = mx[lc(x)]; 51 if (e[mx[rc(x)]].w < e[mx[x]].w) mx[x] = mx[rc(x)]; 52 } 53 54 void rev(int x) { 55 swap(lc(x), rc(x)); 56 tun[x] ^= 1; 57 } 58 59 void pushdown(int x) { 60 if (tun[x]) { 61 if (lc(x)) rev(lc(x)); 62 if (rc(x)) rev(rc(x)); 63 tun[x] = 0; 64 } 65 } 66 67 int st[N << 2], tp; 68 69 void pd(int x) { 70 while (!isroot(x)) { 71 st[++tp] = x; 72 x = f[x]; 73 } 74 pushdown(x); 75 while (tp) pushdown(st[tp--]); 76 } 77 78 void rotate(int x) { 79 int old = f[x], oldf = f[old], son = ch[x][get(x) ^ 1]; 80 if (!isroot(old)) ch[oldf][get(old)] = x; 81 ch[x][get(x) ^ 1] = old; 82 ch[old][get(x)] = son; 83 f[old] = x; f[x] = oldf; f[son] = old; 84 up(old); up(x); 85 } 86 87 void splay (int x) { 88 pd(x); 89 for (; !isroot(x); rotate(x)) 90 if (!isroot(f[x])) 91 rotate(get(f[x]) == get(x) ? f[x] : x); 92 } 93 94 void access(int x) { 95 for (int y = 0; x; y = x, x = f[x]) 96 splay(x), ch[x][1] = y, up(x); 97 } 98 99 void mroot(int x) { 100 access(x); splay(x); rev(x); 101 } 102 103 void split(int x, int y) { 104 mroot(x); access(y); splay(y); 105 } 106 107 int findr(int x) { 108 access(x); splay(x); 109 while (lc(x)) pushdown(x), x = lc(x); 110 return x; 111 } 112 113 void link(int x, int y) { 114 mroot(x); f[x] = y; 115 } 116 117 void cut(int x, int y) { 118 split(x, y); 119 f[x] = ch[y][0] = 0; 120 } 121 } 122 using namespace LCT; 123 124 int main() 125 { 126 n = rd; m = rd; 127 e[0].w = inf; 128 for (int i = 1; i <= m; ++i) { 129 e[i].u = rd; e[i].v = rd; e[i].w = rd; 130 } 131 sort(e + 1, e + 1 + m, cmp); 132 for (int i = 1; i <= m; ++i) 133 val[i + n] = i; 134 for (int i = 1, l = 1, tot = 0; i <= m; ++i) { 135 int x = e[i].u, y = e[i].v; 136 if (x == y) continue; 137 mroot(x); 138 if (findr(y) != x) { 139 link(i + n, y); 140 link(i + n, x); 141 vis[i] = 1; 142 tot++; 143 if (tot == n - 1) { 144 while (!vis[l]) l++; 145 cmin(ans, e[i].w - e[l].w); 146 } 147 } 148 else { 149 int t = mx[y]; 150 cut(t + n, e[t].u); 151 cut(t + n, e[t].v); 152 link(i + n, x); 153 link(i + n, y); 154 vis[t] = 0; vis[i] = 1; 155 if (tot == n - 1) { 156 while (!vis[l]) l++; 157 cmin(ans, e[i].w - e[l].w); 158 } 159 } 160 } 161 printf("%d\n", ans); 162 }