生成树题目泛做(AD第二轮)
题目1: NOI2014 魔法森林
LCT维护MST。解题报告见LOFTER
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdlib> 6 7 using namespace std; 8 9 const int N = 150000 + 5; 10 const int inf = 1e9; 11 12 int n, m, ans = inf; 13 14 struct Edge { 15 int from, to, a, b; 16 bool operator < (const Edge &s) const { 17 return a < s.a; 18 } 19 }e[N]; 20 21 #define L(x) c[x][0] 22 #define R(x) c[x][1] 23 int fa[N], c[N][2], val[N], mx[N], st[N], top; 24 bool rev[N]; 25 26 bool isroot(int x) { 27 return L(fa[x]) != x && R(fa[x]) != x; 28 } 29 30 void pushup(int x) { 31 int l = L(x), r = R(x); 32 33 mx[x] = x; 34 if(l && val[mx[l]] > val[mx[x]]) mx[x] = mx[l]; 35 if(r && val[mx[r]] > val[mx[x]]) mx[x] = mx[r]; 36 } 37 38 void pushdown(int x) { 39 int l = L(x), r = R(x); 40 41 if(rev[x]) { 42 rev[x] ^= 1; rev[l] ^= 1; rev[r] ^= 1; 43 swap(L(x), R(x)); 44 } 45 } 46 47 void rotate(int x) { 48 int y = fa[x], z = fa[y], l, r; 49 50 l = (L(y) == x) ^ 1; r = l ^ 1; 51 if(!isroot(y)) { 52 c[z][(L(z) == y) ^ 1] = x; 53 } 54 fa[x] = z; fa[y] = x; fa[c[x][r]] = y; 55 c[y][l] = c[x][r]; c[x][r] = y; 56 pushup(y); pushup(x); 57 } 58 59 void splay(int x) { 60 top = 0; 61 st[++ top] = x; 62 for(int i = x; fa[i]; i = fa[i]) 63 st[++ top] = fa[i]; 64 while(top) pushdown(st[top --]); 65 while(!isroot(x)) { 66 int y = fa[x], z = fa[y]; 67 68 if(!isroot(y)) { 69 if((L(z) == y) ^ (L(y) == x)) 70 rotate(x); 71 else 72 rotate(y); 73 } 74 rotate(x); 75 } 76 pushup(x); 77 } 78 79 void Access(int x) { 80 int t = 0; 81 82 while(x) { 83 splay(x); 84 c[x][1] = t; 85 t = x; 86 pushup(x); 87 x = fa[x]; 88 } 89 } 90 91 void Makeroot(int x) { 92 Access(x); splay(x); rev[x] ^= 1; 93 } 94 95 int Findroot(int x) { 96 Access(x); splay(x); 97 while(c[x][0]) { 98 x = c[x][0]; 99 } 100 return x; 101 } 102 103 void Cut(int x, int y) { 104 Makeroot(x); Access(y); splay(y); 105 L(y) = fa[L(y)] = 0; 106 } 107 108 void Link(int x, int y) { 109 Makeroot(x); fa[x] = y; 110 } 111 112 int Getpos(int x, int y) { 113 Makeroot(x); Access(y); splay(y); 114 return mx[y]; 115 } 116 int read() { 117 int x = 0; 118 char ch = getchar(); 119 120 while(ch < '0' || ch > '9') ch = getchar(); 121 while(ch <= '9' && ch >= '0') { 122 x = x * 10 + ch - '0'; 123 ch = getchar(); 124 } 125 return x; 126 } 127 128 //#define ONLINE_JUDGE 129 130 int main() { 131 #ifndef ONLINE_JUDGE 132 freopen("magicalforest.in", "r", stdin); 133 freopen("magicalforest.out", "w", stdout); 134 #endif 135 136 n = read(); m = read(); 137 for(int i = 1; i <= m; ++ i) { 138 e[i].from = read(); e[i].to = read(); 139 e[i].a = read(); e[i].b = read(); 140 } 141 sort(e + 1, e + m + 1); 142 for(int i = 1; i <= m; ++ i) { 143 val[i + n] = e[i].b; 144 mx[i + n] = i + n; 145 } 146 for(int i = 1; i <= m; ++ i) { 147 if(Findroot(e[i].from) == Findroot(e[i].to)) { 148 int tmp = Getpos(e[i].from, e[i].to); 149 150 if(val[tmp] > e[i].b) { 151 Cut(e[i].from, tmp); Cut(e[i].to,tmp); 152 Link(e[i].from, i + n); Link(e[i].to, i + n); 153 } 154 } 155 else { 156 Link(e[i].from, i + n); Link(e[i].to, i + n); 157 } 158 if(Findroot(1) == Findroot(n)) { 159 ans = min(ans, e[i].a + val[Getpos(1, n)]); 160 } 161 } 162 printf("%d\n", ans == inf ? -1 : ans); 163 164 #ifndef ONLINE_JUDGE 165 fclose(stdin); fclose(stdout); 166 #endif 167 168 return 0; 169 }
题目2: WC2006 水管局长
LCT维护MST。解题报告见LOFTER
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdlib> 6 7 using namespace std; 8 9 const int N = 200000 + 5; 10 const int M = 1000000 + 5 + N; 11 const int Q = 100000 + 5; 12 13 int read() { 14 int x = 0; 15 char ch = getchar(); 16 17 while(ch < '0' || ch > '9') ch = getchar(); 18 while(ch <= '9' && ch >= '0') { 19 x = x * 10 + ch - '0'; 20 ch = getchar(); 21 } 22 return x; 23 } 24 25 int n, m, q; 26 27 struct Edge { 28 int from, to, dis, id; 29 bool del; 30 }e[M]; 31 struct Query { 32 int type, from, to, id, ans; 33 }w[Q]; 34 35 #define L(x) c[x][0] 36 #define R(x) c[x][1] 37 int fa[M], c[M][2], val[M], mx[M], st[M], top; 38 bool rev[M]; 39 40 void pushup(int x) { 41 int l = L(x), r = R(x); 42 43 mx[x] = x; 44 if(l && val[mx[l]] > val[mx[x]]) mx[x] = mx[l]; 45 if(r && val[mx[r]] > val[mx[x]]) mx[x] = mx[r]; 46 } 47 48 void pushdown(int x) { 49 int l = L(x), r = R(x); 50 51 if(rev[x]) { 52 rev[x] ^= 1; rev[l] ^= 1; rev[r] ^= 1; 53 swap(c[x][1], c[x][0]); 54 } 55 } 56 57 bool isroot(int x) { 58 return L(fa[x]) != x && R(fa[x]) != x; 59 } 60 61 void rotate(int x) { 62 int y = fa[x], z = fa[y], l, r; 63 64 l = (L(y) == x) ^ 1; r = l ^ 1; 65 if(!isroot(y)) { 66 c[z][(L(z) == y) ^ 1] = x; 67 } 68 fa[x] = z; fa[y] = x; fa[c[x][r]] = y; 69 c[y][l] = c[x][r]; c[x][r] = y; 70 pushup(y); pushup(x); 71 } 72 73 void Splay(int x) { 74 top = 0; 75 st[++ top] = x; 76 for(int i = x; fa[i]; i = fa[i]) 77 st[++ top] = fa[i]; 78 while(top) pushdown(st[top --]); 79 while(!isroot(x)) { 80 int y = fa[x], z = fa[y]; 81 82 if(!isroot(y)) { 83 if((L(z) == y) ^ (L(y) == x)) 84 rotate(x); 85 else 86 rotate(y); 87 } 88 rotate(x); 89 } 90 pushup(x); 91 } 92 93 void Access(int x) { 94 int t = 0; 95 96 while(x) { 97 Splay(x); 98 c[x][1] = t; 99 t = x; 100 pushup(x); 101 x = fa[x]; 102 } 103 } 104 105 void Makeroot(int x) { 106 Access(x); Splay(x); rev[x] ^= 1; 107 } 108 109 int Findroot(int x) { 110 Access(x); Splay(x); 111 while(c[x][0]) { 112 x = c[x][0]; 113 } 114 return x; 115 } 116 117 void Cut(int x, int y) { 118 Makeroot(x); Access(y); Splay(y); 119 L(y) = fa[L(y)] = 0; 120 } 121 122 void Link(int x, int y) { 123 Makeroot(x); fa[x] = y; 124 } 125 126 int Getpos(int x, int y) { 127 Makeroot(x); Access(y); Splay(y); 128 return mx[y]; 129 } 130 131 bool cmpdis(Edge a, Edge b) { 132 return a.dis < b.dis; 133 } 134 135 bool cmpnode(Edge a, Edge b) { 136 if(a.from == b.from) return a.to < b.to; 137 return a.from < b.from; 138 } 139 140 bool cmpid(Edge a, Edge b) { 141 return a.id < b.id; 142 } 143 144 int ufs[N]; 145 146 int find(int x) { 147 return ufs[x] == x ? x : ufs[x] = find(ufs[x]); 148 } 149 150 int search(int u, int v) { 151 int l = 1, r = m, mid, res; 152 153 while(l <= r) { 154 mid = l + (r - l) / 2; 155 if(e[mid].from < u || (e[mid].from == u && e[mid].to < v)) { 156 l = mid + 1; 157 } 158 else { 159 r = mid - 1; 160 res = mid; 161 } 162 } 163 return res; 164 } 165 int main() { 166 #ifndef ONLINE_JUDGE 167 freopen("tube_strong.in", "r", stdin); 168 freopen("tube_strong.out", "w", stdout); 169 #endif 170 171 int tp1, tp2, have = 0; 172 173 n = read(); m = read(); q = read(); 174 for(int i = 1; i <= m; ++ i) { 175 e[i].from = read(); e[i].to = read(); e[i].dis = read(); 176 if(e[i].from > e[i].to) swap(e[i].from, e[i].to); 177 } 178 for(int i = 1; i <= q; ++ i) { 179 w[i].type = read(); w[i].from = read(); w[i].to = read(); 180 } 181 sort(e + 1, e + m + 1, cmpdis); 182 for(int i = 1; i <= m; ++ i) { 183 e[i].id = i; 184 val[i + n] = e[i].dis; 185 mx[i + n] = i + n; 186 } 187 sort(e + 1, e + m + 1, cmpnode); 188 for(int i = 1; i <= q; ++ i) { 189 if(w[i].type == 2) { 190 if(w[i].from > w[i].to) swap(w[i].from, w[i].to); 191 tp1 = search(w[i].from, w[i].to); 192 e[tp1].del = true; w[i].id = e[tp1].id; 193 } 194 } 195 sort(e + 1, e + m + 1, cmpid); 196 for(int i = 1; i <= n; ++ i) ufs[i] = i; 197 for(int i = 1; i <= m; ++ i) { 198 if(e[i].del) continue; 199 200 int fx = find(e[i].from), fy = find(e[i].to); 201 202 if(fx != fy) { 203 ufs[fx] = fy; 204 Link(e[i].from, i + n); 205 Link(e[i].to, i + n); 206 ++ have; 207 if(have == n - 1) break; 208 } 209 } 210 for(int i = q; i >= 1; -- i) { 211 if(w[i].type == 1) { 212 w[i].ans = val[Getpos(w[i].from, w[i].to)]; 213 } 214 else { 215 tp1 = Getpos(w[i].from, w[i].to); 216 tp2 = w[i].id; 217 if(e[tp2].dis < e[tp1 - n].dis) { 218 Cut(e[tp1 - n].from, tp1); Cut(e[tp1 - n].to, tp1); 219 Link(w[i].from, tp2 + n); Link(w[i].to, tp2 + n); 220 } 221 } 222 } 223 for(int i = 1; i <= q; ++ i) { 224 if(w[i].type == 1) 225 printf("%d\n", w[i].ans); 226 } 227 228 #ifndef ONLINE_JUDGE 229 fclose(stdin); fclose(stdout); 230 #endif 231 return 0; 232 }
题目3: POJ 3241
求曼哈顿距离最小生成树上的第k大边。也就是第n-k小边。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cstdlib> 6 7 using namespace std; 8 9 const int N = 10000 + 5; 10 const int M = 50000 + 5; 11 12 int n, k, ans, cnt; 13 int a[N], b[N], fa[N]; 14 15 struct Point { 16 int x, y, id; 17 18 bool operator < (const Point &a) const { 19 if(a.x == x) return y < a.y; 20 return x < a.x; 21 } 22 }p[N]; 23 24 struct Edge { 25 int from, to, dis; 26 27 bool operator < (const Edge &a) const { 28 return dis < a.dis; 29 } 30 }e[M]; 31 32 struct Bit { 33 int val, pos; 34 void init() { 35 pos = -1; 36 val = (1<<30); 37 } 38 }c[N]; 39 40 int dist(int x, int y) { 41 return abs(x) + abs(y); 42 } 43 44 int find(int x) { 45 return fa[x] == x ? x : fa[x] = find(fa[x]); 46 } 47 48 int query(int x, int m) { 49 int Min = (1<<30), res = -1; 50 51 for(int i = x; i <= m; i += (i&(-i))) 52 if(c[i].val < Min) { 53 Min = c[i].val; 54 res = c[i].pos; 55 } 56 return res; 57 } 58 59 void update(int x, int val, int pos) { 60 for(int i = x; i > 0; i -= (i&(-i))) 61 if(val < c[i].val) { 62 c[i].val = val; 63 c[i].pos = pos; 64 } 65 } 66 67 void mst() { 68 int m, have; 69 70 for(int dir = 0; dir < 4; ++ dir) { 71 if(dir & 1) 72 for(int i = 1; i <= n; ++ i) 73 swap(p[i].x, p[i].y); 74 else if(dir == 2) 75 for(int i = 1; i <= n; ++ i) 76 p[i].x = -p[i].x; 77 sort(p + 1, p + n + 1); 78 for(int i = 1; i <= n; ++ i) 79 a[i] = b[i] = p[i].y - p[i].x; 80 sort(b + 1, b + n + 1); 81 m = unique(b + 1, b + n + 1) - b - 1; 82 for(int i = 1; i <= m; ++ i) c[i].init(); 83 for(int i = n; i >= 1; -- i) { 84 int pos = lower_bound(b + 1, b + m + 1, a[i]) - b; 85 int ans = query(pos, m); 86 87 if(ans != -1) { 88 ++ cnt; 89 e[cnt].from = p[i].id; 90 e[cnt].to = p[ans].id; 91 e[cnt].dis = dist(p[i].x - p[ans].x, p[i].y - p[ans].y); 92 } 93 update(pos, p[i].x + p[i].y, i); 94 } 95 } 96 have = 0; 97 sort(e + 1, e + cnt + 1); 98 for(int i = 1; i <= n; ++ i) fa[i] = i; 99 for(int i = 1; i <= cnt; ++ i) { 100 int fx = find(e[i].from), fy = find(e[i].to); 101 102 if(fx != fy) { 103 fa[fx] = fy; 104 ++ have; 105 ans = e[i].dis; 106 if(have == n - k) break; 107 } 108 } 109 } 110 111 int main() { 112 scanf("%d%d", &n, &k); 113 for(int i = 1; i <= n; ++ i) { 114 scanf("%d%d", &p[i].x, &p[i].y); 115 p[i].id = i; 116 } 117 mst(); 118 printf("%d", ans); 119 return 0; 120 }
题目4: 繁忙的都市BZOJ1083 BZOJ2429聪明的猴子
这两是裸题。不写了。
题目5:Uva11354 Bond NOIP 货车运输
货车运输,求最大生成树,用lca维护路径上最大值。
1 /* 2 Problem: Truck NOIP 3 Author: Bs.yx 4 Date: 2015/11/04 p.m. 5 Algorithm LCA + Kruscal->MBT 6 */ 7 #include <cstdio> 8 #include <cstring> 9 #include <cstdlib> 10 #include <algorithm> 11 #include <iostream> 12 13 using namespace std; 14 const int maxnode = 10000+5; 15 const int maxm = 50000 + 5; 16 17 int N,M,Q,root; 18 int tot=0,tot_e=0; 19 int fa[maxnode],depth[maxnode]; 20 int p[maxnode][15],mi[maxnode][15],cost[maxnode]; 21 int first[maxnode],next[maxm*2]; 22 int u[maxm*2],v[maxm*2],w[maxm*2]; 23 struct Edge{ 24 int from,to,dis; 25 bool operator < (const Edge&a)const{ 26 return dis > a.dis; 27 } 28 }e[maxm*2]; 29 30 int find(int); 31 void prepare(); 32 void dfs(int); 33 int lca(int,int); 34 void Kruscal(); 35 void Add(int,int,int); 36 37 int main(){ 38 freopen("truck.in","r",stdin); 39 freopen("truck.out","w",stdout); 40 int x,y,z; 41 memset(p,-1,sizeof p); 42 memset(mi,127/3,sizeof mi); 43 scanf("%d%d",&N,&M); 44 for(int i = 1;i <= M;++ i){ 45 scanf("%d%d%d",&x,&y,&z); 46 ++ tot_e; 47 e[tot_e].from = x;e[tot_e].to = y; 48 e[tot_e].dis = z; 49 } 50 Kruscal(); 51 depth[root] = 1; 52 dfs(root);prepare(); 53 scanf("%d",&Q); 54 for(int i = 1;i <= Q;++ i){ 55 scanf("%d%d",&x,&y); 56 int fx = find(x),fy = find(y); 57 if(fx != fy){printf("-1\n");continue;} 58 int dst = lca(x,y); 59 printf("%d\n",dst); 60 } 61 62 return 0; 63 } 64 65 int find(int x){ 66 return fa[x] == x ? (x) : (fa[x] = find(fa[x])); 67 } 68 void dfs(int now){ 69 for(int i = first[now];i;i = next[i]){ 70 if(!depth[v[i]]){ 71 depth[v[i]] = depth[now] + 1; 72 p[v[i]][0] = now;cost[v[i]] = w[i]; 73 dfs(v[i]); 74 } 75 } 76 } 77 void prepare(){ 78 for(int i = 1;i <= N;++ i){ 79 mi[i][0] = cost[i]; 80 } 81 for(int j = 1;(1<<j) <= N;++ j){ 82 for(int i = 1;i <= N;++ i){ 83 if(p[i][j-1] != -1){ 84 p[i][j] = p[p[i][j-1]][j-1]; 85 mi[i][j] = min(mi[i][j-1],mi[p[i][j-1]][j-1]); 86 } 87 } 88 } 89 } 90 int lca(int a,int b){ 91 int i,ret = 0x7fffffff; 92 if(depth[a] < depth[b]) 93 a ^= b ^= a ^= b; 94 for(i = 0;(1<<i) <= N;++ i); 95 i --; 96 97 for(int j = i;j >= 0;-- j) 98 if(depth[a] - depth[b] >= (1<<j)){ 99 ret = min(ret,mi[a][j]); 100 a = p[a][j]; 101 } 102 // if(a == b)return a; 103 if(a == b)return ret; 104 for(int j = i;j >= 0;-- j) 105 if(p[a][j] != -1 && p[a][j] != p[b][j]){ 106 ret = min(ret,mi[a][j]); 107 ret = min(ret,mi[b][j]); 108 a = p[a][j];b = p[b][j]; 109 } 110 ret = min(ret,cost[a]); 111 ret = min(ret,cost[b]); 112 return ret; 113 // return p[a][0]; 114 } 115 void Kruscal(){ 116 int have=0; 117 for(int i = 1;i <= N;++ i)fa[i] = i; 118 sort(e + 1,e + tot_e + 1); 119 120 for(int i = 1;i <= tot_e;++ i){ 121 int fx = find(e[i].from),fy = find(e[i].to); 122 if(fx != fy){ 123 fa[fx] = fy; 124 root = e[i].from; 125 Add(e[i].from,e[i].to,e[i].dis); 126 Add(e[i].to,e[i].from,e[i].dis); 127 ++ have; 128 } 129 } 130 return; 131 } 132 void Add(int s,int t,int ww){ 133 ++ tot; 134 u[tot] = s;v[tot] = t;w[tot] = ww; 135 next[tot] = first[u[tot]]; 136 first[u[tot]] = tot; 137 }
题目6:BZOJ 1601 灌水
算法讨论:
虚拟一个根节点做MST。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdlib> 6 7 using namespace std; 8 9 int N,x,cost,tot_e=0; 10 int w[305],fa[305]; 11 struct data{ 12 int from,to,dis; 13 bool operator < (const data&a)const { 14 return dis < a.dis; 15 } 16 }e[100005]; 17 18 int find(int); 19 void Kruscal(); 20 void Add(int,int,int); 21 22 int main(){ 23 scanf("%d",&N); 24 for(int i = 1;i <= N;++ i){ 25 scanf("%d",&w[i]); 26 } 27 for(int i = 1;i <= N;++ i){ 28 for(int j = 1;j <= N;++ j){ 29 scanf("%d",&x); 30 Add(i,j,x); 31 } 32 } 33 for(int i = 1;i <= N;++ i){ 34 Add(N+1,i,w[i]); 35 } 36 Kruscal(); 37 return 0; 38 } 39 40 void Add(int s,int t,int v){ 41 ++ tot_e; 42 e[tot_e].from = s; 43 e[tot_e].to = t; 44 e[tot_e].dis = v; 45 } 46 int find(int x){ 47 return fa[x] == x ? (x) : (fa[x] = find(fa[x])); 48 } 49 void Kruscal(){ 50 int tot = 0; 51 sort(e+1,e+tot_e+1); 52 for(int i = 1;i <= N;++ i)fa[i] = i; 53 for(int i = 1;i <= tot_e;++ i){ 54 int fx = find(e[i].from),fy = find(e[i].to); 55 if(fx != fy){ 56 ++ tot; 57 fa[fx] = fy; 58 cost += e[i].dis; 59 if(tot == N) 60 break; 61 } 62 } 63 printf("%d\n",cost); 64 return; 65 }
题目7: BZOJ 1232 安慰奶牛
算法讨论:我们考虑每条边都被经过两次,所以把点权放到边权上,最后找一个安慰时间最小的点做为MST的根就行。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 7 using namespace std; 8 const int maxn = 200000 + 5; 9 10 int N,M,x,y,z; 11 int minn = 0x7fffffff; 12 int w[maxn],cost=0,fa[maxn]; 13 int tot_e; 14 struct Edge{ 15 int from,to,dis; 16 bool operator < (const Edge&a)const { 17 return dis < a.dis; 18 } 19 }e[maxn]; 20 21 22 void Add(int,int,int); 23 void Kruscal(); 24 int find(int x); 25 26 int main(){ 27 scanf("%d%d",&N,&M); 28 for(int i = 1;i <= N;++ i){ 29 scanf("%d",&w[i]); 30 minn = min(w[i],minn); 31 } 32 for(int i = 1;i <= M;++ i){ 33 scanf("%d%d%d",&x,&y,&z); 34 Add(x,y,z*2+w[x]+w[y]); 35 Add(y,x,z*2+w[x]+w[y]); 36 } 37 Kruscal(); 38 printf("%d\n",cost+minn); 39 return 0; 40 } 41 42 int find(int x){ 43 return fa[x] == x ? (x):(fa[x] = find(fa[x])); 44 } 45 void Kruscal(){ 46 int h = 0; 47 sort(e+1,e+tot_e+1); 48 for(int i = 1;i <= N;++ i)fa[i] = i; 49 50 for(int i = 1;i <= tot_e;++ i){ 51 int fx = find(e[i].from),fy = find(e[i].to); 52 if(fx != fy){ 53 ++ h; 54 cost += e[i].dis; 55 fa[fx] = fy; 56 if(h == N-1) 57 break; 58 } 59 } 60 return; 61 } 62 63 void Add(int s,int t,int ww){ 64 ++ tot_e; 65 e[tot_e].from = s; 66 e[tot_e].to = t; 67 e[tot_e].dis = ww; 68 }
题目8:Uva 10369
NOIP考试题。水死。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 #define N 510 7 #define INF 1000000000.000 8 double g[N][N]; 9 int x[N],y[N]; 10 int n,m; //有m个卫星 11 12 double dis(int i ,int j) 13 { return sqrt( 1.*(x[i]-x[j])*(x[i]-x[j])+1.*(y[i]-y[j])*(y[i]-y[j]) ); } 14 15 16 void prim() 17 { 18 double lowcost[N],ans[N]; 19 int adj[N],cov[N]; 20 for(int i=2; i<=n; i++) 21 { 22 lowcost[i]=g[1][i]; 23 adj[i]=1; 24 cov[i]=0; 25 } 26 lowcost[1]=0; adj[1]=1; cov[1]=1; 27 28 for(int nn=1; nn<n; nn++) //还有纳入n-1个点 29 { 30 double min=INF; 31 int k=1; 32 for(int i=1; i<=n; i++) 33 if(!cov[i] && lowcost[i]<min) 34 { 35 min=lowcost[i]; 36 k=i; 37 } 38 //printf("%.2f\n",min); 39 ans[nn]=min; 40 cov[k]=1; 41 42 for(int i=1; i<=n; i++) 43 if(!cov[i] && lowcost[i] > g[k][i]) 44 { 45 lowcost[i]=g[k][i]; 46 adj[i]=k; 47 } 48 } 49 50 sort(ans+1 , ans+n); 51 /* 52 for(int i=1; i<n; i++) 53 printf("%.2f\n",ans[i]); 54 */ 55 printf("%.2lf\n",ans[n-m]); 56 return ; 57 } 58 int main() 59 { 60 int T; 61 scanf("%d",&T); 62 while(T--) 63 { 64 scanf("%d%d",&m,&n); 65 for(int i=1; i<=n; i++) 66 scanf("%d%d",&x[i],&y[i]); 67 68 for(int i=1; i<=n; i++) g[i][i]=0; 69 70 for(int i=1; i<=n; i++) 71 for(int j=i+1; j<=n; j++) 72 g[i][j]=g[j][i]=dis(i,j); 73 74 prim(); 75 } 76 return 0; 77 }
题目9: Uva1395
求最小瓶径生成树。就是最小生成树上的最大边。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstdlib> 6 using namespace std; 7 8 typedef long long ll; 9 const int N = 105; 10 const int M = N * (N - 1) / 2; 11 const int INF = 0x3f3f3f3f; 12 int n, m; 13 int f[N]; 14 15 struct Node{ 16 int x, y, len; 17 }q[M]; 18 19 int find(int x) { 20 return f[x] == x ? x : f[x] = find(f[x]); 21 } 22 23 void init() { 24 for (int i = 0; i <= n; i++) f[i] = i; 25 } 26 27 int cmp(Node a, Node b) { 28 return a.len < b.len; 29 } 30 31 void input() { 32 for (int i = 0; i < m; i++) { 33 scanf("%d %d %d", &q[i].x, &q[i].y, &q[i].len); 34 } 35 sort(q, q + m, cmp); 36 } 37 38 int kruskal(int s) { 39 int cnt = 0, Max; 40 for (int i = s; i < m; i++) { 41 int x = find(q[i].x), y = find(q[i].y); 42 if (x != y) { 43 f[x] = y; 44 cnt++; 45 if (cnt == n - 1) Max = q[i].len; 46 } 47 } 48 if (cnt != n - 1) return INF; 49 return Max - q[s].len; 50 } 51 52 void solve() { 53 int ans = INF; 54 for (int i = 0; i <= m - n + 1; i++) { 55 init(); 56 int temp = ans; 57 ans = min(ans, kruskal(i)); 58 } 59 if (ans == INF) printf("-1\n"); 60 else printf("%d\n", ans); 61 } 62 63 int main() { 64 while (scanf("%d %d", &n, &m) == 2) { 65 if (!n && !m) break; 66 if (m < n - 1) { 67 int a, b, c; 68 for (int i = 0; i < m; i++) scanf("%d %d %d", &a, &b, &c); 69 printf("-1\n"); 70 continue; 71 } 72 input(); 73 solve(); 74 } 75 return 0; 76 }
题目10: BZOJ 1050 旅行
两个变量,定一求一。枚举最小边,做MST
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 500 + 5; 6 const int M = 5000 + 5; 7 8 int n, m, s, t; 9 double ans = 1000000000.000; 10 int ans_x, ans_y; 11 int fa[N]; 12 13 struct Edge { 14 int from, to, dis; 15 bool operator < (const Edge &a) const { 16 return dis < a.dis; 17 } 18 }e[M]; 19 20 int find(int x) { 21 return fa[x] == x ? x : fa[x] = find(fa[x]); 22 } 23 24 int gcd(int a, int b) { 25 return b == 0 ? a : gcd(b, a % b); 26 } 27 #define ONLINE_JUDGE 28 int main() { 29 #ifndef ONLINE_JUDGE 30 freopen("comf.in", "r", stdin); 31 freopen("comf.out", "w", stdout); 32 #endif 33 34 bool flag = false; 35 36 scanf("%d%d", &n, &m); 37 for(int i = 1; i <= m; ++ i) { 38 scanf("%d%d%d", &e[i].from, &e[i].to, &e[i].dis); 39 } 40 scanf("%d%d", &s, &t); 41 42 sort(e + 1, e + m + 1); 43 for(int i = 1; i <= m; ++ i) { 44 int minn = 0x3f3f3f3f, maxx = 0; 45 int have = 0; 46 47 for(int j = 1; j <= n; ++ j) fa[j] = j; 48 have ++; 49 fa[e[i].from] = e[i].to; 50 minn = min(minn, e[i].dis); 51 maxx = max(maxx, e[i].dis); 52 if(find(s) == find(t)) { 53 puts("1"); 54 return 0; 55 } 56 for(int j = i + 1; j <= m; ++ j) { 57 int fx = find(e[j].from), fy = find(e[j].to); 58 59 if(fx != fy) { 60 fa[fx] = fy; 61 have ++; 62 minn = min(minn, e[j].dis); 63 maxx = max(maxx, e[j].dis); 64 if(find(s) == find(t)){ 65 flag = true; 66 if((double) maxx * 1000 / minn < ans) { 67 ans_x = maxx; ans_y = minn; 68 ans = (double) maxx * 1000 / minn; 69 } 70 break; 71 } 72 } 73 } 74 } 75 76 if(!flag) { 77 puts("IMPOSSIBLE"); 78 return 0; 79 } 80 81 int temp = gcd(ans_x, ans_y); 82 83 ans_x /= temp; ans_y /= temp; 84 if(ans_y == 1) { 85 printf("%d", ans_x); 86 } 87 else { 88 printf("%d/%d", ans_x, ans_y); 89 } 90 91 #ifndef ONLINE_JUDGE 92 fclose(stdin); fclose(stdout); 93 #endif 94 return 0; 95 }
题目11: POJ 1679
非严格次小生成树。就是判断最小生成树是否唯一。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cstdio> 6 7 using namespace std; 8 9 const int N = 100 + 5; 10 const int M = 300000 + 5; 11 typedef long long ll; 12 13 int n, m, cnt = 0; 14 int head[N], depth[N]; 15 int fa[N][18], father[N]; 16 ll cost[N], mx[N][18]; 17 18 struct Edge { 19 int u, v; 20 ll dis; 21 bool flag; 22 bool operator < (const Edge &a) const { 23 return dis < a.dis; 24 } 25 }e[M]; 26 27 struct linksheet { 28 int u, v, next; 29 ll dis; 30 }edges[N<<1]; 31 32 int find(int x) { 33 return father[x] == x ? x : father[x] = find(father[x]); 34 } 35 36 void insert(int u, int v, int w) { 37 ++ cnt; 38 edges[cnt].u = u; 39 edges[cnt].v = v; 40 edges[cnt].dis = w; 41 edges[cnt].next = head[u]; 42 head[u] = cnt; 43 } 44 45 void dfs(int cur) { 46 for(int i = head[cur]; i; i = edges[i].next) { 47 int v = edges[i].v; 48 49 if(!depth[v]) { 50 depth[v] = depth[cur] + 1; 51 fa[v][0] = cur; 52 cost[v] = edges[i].dis; 53 dfs(v); 54 } 55 } 56 } 57 58 void prepare() { 59 memset(mx, 0, sizeof mx); 60 for(int i = 1; i <= n; ++ i) 61 mx[i][0] = cost[i]; 62 for(int j = 1; (1<<j) <= n; ++ j) { 63 for(int i = 1; i <= n; ++ i) { 64 if(fa[i][j - 1] != -1) { 65 fa[i][j] = fa[fa[i][j - 1]][j - 1]; 66 mx[i][j] = max(mx[i][j - 1], mx[fa[i][j - 1]][j - 1]); 67 } 68 } 69 } 70 } 71 72 int lca(int a, int b) { 73 int i; 74 ll res = 0; 75 76 if(depth[a] < depth[b]) 77 swap(a, b); 78 for(i = 0; (1<<i) <= n; ++ i); 79 -- i; 80 for(int j = i; j >= 0; -- j) 81 if(depth[a] - depth[b] >= (1<<j)) { 82 res = max(res, mx[a][j]); 83 a = fa[a][j]; 84 } 85 if(a == b) return res; 86 for(int j = i; j >= 0; -- j) { 87 if(fa[a][j] != -1 && fa[a][j] != fa[b][j]) { 88 res = max(res, mx[a][j]); 89 res = max(res, mx[b][j]); 90 a = fa[a][j]; b = fa[b][j]; 91 } 92 } 93 res = max(cost[a], res); 94 res = max(cost[b], res); 95 96 return res; 97 } 98 99 int main() { 100 int t; 101 102 scanf("%d", &t); 103 104 while(t --) { 105 int have = 0; 106 ll mst = 0; 107 cnt = 0; 108 memset(depth, 0, sizeof depth); 109 memset(head, 0, sizeof head); 110 111 scanf("%d%d", &n, &m); 112 for(int i = 1; i <= m; ++ i) { 113 scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].dis); 114 e[i].flag = false; 115 } 116 sort(e + 1, e + m + 1); 117 for(int i = 1; i <= n; ++ i) father[i] = i; 118 for(int i = 1; i <= m; ++ i) { 119 int fx = find(e[i].u), fy = find(e[i].v); 120 121 if(fx != fy) { 122 father[fx] = fy; 123 ++ have; 124 mst += e[i].dis; 125 insert(e[i].u, e[i].v, e[i].dis); 126 insert(e[i].v, e[i].u, e[i].dis); 127 e[i].flag = true; 128 if(have == n - 1) break; 129 } 130 } 131 if(have < n - 1) { 132 puts("Not Unique!"); 133 continue; 134 } 135 136 ll ans = 100000000000000000LL; 137 138 memset(fa, -1, sizeof fa); 139 depth[1] = 1; dfs(1); 140 prepare(); 141 for(int i = 1; i <= m; ++ i) { 142 if(!e[i].flag) { 143 ll tmp = lca(e[i].u, e[i].v); 144 ans = min(ans, mst - tmp + e[i].dis); 145 } 146 } 147 148 if(ans == mst) { 149 puts("Not Unique!"); 150 } 151 else { 152 printf("%lld\n", mst); 153 } 154 } 155 return 0; 156 }
题目12: HDu 4081
这个题不难,没耐心做了。直接贴得代码。次小生成树的问题
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 const int N=1010; 5 const double inf=1e14; 6 using namespace std; 7 8 struct Point{ 9 int x,y,z; 10 }point[N]; 11 12 int n; 13 double edge[N][N]; 14 int nearvex[N];//保存前驱 15 double lowcost[N]; 16 double sum; 17 18 int used[N][N]; 19 int visited[N]; 20 double Max[N][N];//用来保存最小生成树中两点之间的权值最大的边 21 22 23 void prim(int v0){ 24 sum=0; 25 memset(used,0,sizeof(used)); 26 memset(visited,0,sizeof(visited)); 27 memset(Max,0,sizeof(Max)); 28 for(int i=1;i<=n;i++){ 29 lowcost[i]=edge[v0][i]; 30 nearvex[i]=v0; 31 } 32 visited[v0]=1; 33 for(int i=1;i<n;i++){ 34 double min=inf; 35 int v=-1; 36 for(int j=1;j<=n;j++){ 37 if(!visited[j]&&lowcost[j]<min){ 38 v=j,min=lowcost[j]; 39 } 40 } 41 if(v!=-1){ 42 sum+=lowcost[v]; 43 used[v][nearvex[v]]=used[nearvex[v]][v]=1;//标记这条边已经是最小使用过// 44 visited[v]=1; 45 for(int k=1;k<=n;k++){ 46 if(visited[k]&&k!=v){ 47 //对于那些已经加入最小生成树的边,只要每次更新所有点到新加入的点之间的边权值最大值即可 48 Max[v][k]=Max[k][v]=(Max[k][nearvex[v]]>lowcost[v]?Max[k][nearvex[v]]:lowcost[v]); 49 } 50 if(!visited[k]&&edge[v][k]<lowcost[k]){ 51 lowcost[k]=edge[v][k]; 52 nearvex[k]=v; 53 } 54 } 55 } 56 } 57 } 58 59 60 int main(){ 61 int t; 62 scanf("%d",&t); 63 while(t--){ 64 scanf("%d",&n); 65 for(int i=1;i<=n;i++){ 66 scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].z); 67 } 68 for(int i=1;i<=n;i++){ 69 edge[i][i]=0; 70 for(int j=i+1;j<=n;j++){ 71 double dis=sqrt(pow((point[i].x-point[j].x)*1.0,2)+pow((point[i].y-point[j].y)*1.0,2)); 72 edge[i][j]=edge[j][i]=dis; 73 } 74 } 75 prim(1); 76 double r=-1; 77 for(int i=1;i<=n;i++){ 78 for(int j=1;j<=n;j++)if(i!=j){ 79 if(used[i][j]){ 80 r=(r>(point[i].z+point[j].z)*1.0/(sum-edge[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-edge[i][j])); 81 }else if(!used[i][j]){ 82 r=(r>(point[i].z+point[j].z)*1.0/(sum-Max[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-Max[i][j])); 83 } 84 } 85 } 86 printf("%.2lf\n",r); 87 } 88 return 0; 89 }
题目13: POJ 3164
最小树形图。朱刘算法模板题。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <vector> 7 #include <cmath> 8 9 using namespace std; 10 11 const int N = 100 + 5; 12 const int M = 10000 + 5; 13 const double inf = 10000000; 14 15 int n, m; 16 double in[N]; 17 int idx[N], vis[N], pre[N]; 18 19 struct Point { 20 double x, y; 21 }p[N]; 22 23 struct Edge { 24 int from, to; 25 double dis; 26 }e[M]; 27 28 double dist(double a, double b, double c, double d) { 29 return sqrt(pow(a - c, 2) + pow(b - d, 2)); 30 } 31 32 double zhuliuMST(int root) { 33 double res = 0; 34 35 memset(pre, 0, sizeof pre); 36 for(;;) { 37 for(int i = 0; i < n; ++ i) in[i] = inf; 38 for(int i = 1; i <= m; ++ i) { 39 int u = e[i].from, v = e[i].to; 40 41 if(e[i].dis < in[v] && u != v) { 42 pre[v] = u; 43 in[v] = e[i].dis; 44 } 45 } 46 for(int i = 0; i < n; ++ i) { 47 if(i == root) continue; 48 if(in[i] == inf) return -1; 49 } 50 51 int cnt = 0; 52 53 memset(idx, -1, sizeof idx); 54 memset(vis, -1, sizeof vis); 55 in[root] = 0; 56 for(int i = 0; i < n; ++ i) { 57 res += in[i]; 58 59 int v = i; 60 61 while(vis[v] != i && idx[v] == -1 && v != root) { 62 vis[v] = i; 63 v = pre[v]; 64 } 65 if(v != root && idx[v] == -1) { 66 for(int u = pre[v]; u != v; u = pre[u]) { 67 idx[u] = cnt; 68 } 69 idx[v] = cnt ++; 70 } 71 } 72 if(cnt == 0) break; 73 for(int i = 0; i < n; ++ i) 74 if(idx[i] == -1) { 75 idx[i] = cnt ++; 76 } 77 for(int i = 1; i <= m; ++ i) { 78 int v = e[i].to; 79 80 e[i].from = idx[e[i].from]; 81 e[i].to = idx[e[i].to]; 82 if(e[i].from != e[i].to) { 83 e[i].dis -= in[v]; 84 } 85 } 86 root = idx[root]; 87 n = cnt; 88 } 89 90 return res; 91 } 92 93 int main() { 94 while(~scanf("%d%d", &n, &m)) { 95 for(int i = 0; i < n; ++ i) { 96 scanf("%lf%lf", &p[i].x, &p[i].y); 97 } 98 for(int i = 1; i <= m; ++ i) { 99 scanf("%d%d", &e[i].from, &e[i].to); 100 e[i].from --; e[i].to --; 101 if(e[i].from == e[i].to) 102 e[i].dis = inf; 103 else e[i].dis = dist(p[e[i].from].x, p[e[i].from].y, p[e[i].to].x, p[e[i].to].y); 104 } 105 106 double ans = zhuliuMST(0); 107 108 if(ans == -1) { 109 puts("poor snoopy"); 110 } 111 else { 112 printf("%.2f\n", ans); 113 } 114 } 115 116 return 0; 117 }
题目14:HDU 2121
最小树形图。朱刘算法模板题。
这个题要加虚拟节点。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int M = 20000 + 5; 10 const int N = 1000 + 5; 11 typedef long long ll; 12 const ll inf = 10000000000000000LL; 13 14 int n, m, rt; 15 ll sum = 0, in[N]; 16 int vis[N], idx[N], pre[N]; 17 18 struct Edge { 19 int from, to; 20 ll dis; 21 }e[M]; 22 23 ll zhuliuMST(int root, int V, int E) { 24 ll res = 0; 25 26 for(;;) { 27 for(int i = 0; i < V; ++ i) in[i] = inf; 28 for(int i = 0; i < E; ++ i) { 29 int u = e[i].from, v = e[i].to; 30 31 if(e[i].dis < in[v] && v != u) { 32 in[v] = e[i].dis; 33 pre[v] = u; 34 if(u == root) 35 rt = i; 36 } 37 } 38 for(int i = 0; i < V; ++ i) { 39 if(i == root) continue; 40 if(in[i] == inf) return -1; 41 } 42 43 int cnt = 0; 44 45 memset(idx, -1, sizeof idx); 46 memset(vis, -1, sizeof vis); 47 in[root] = 0; 48 for(int i = 0; i < V; ++ i) { 49 res += in[i]; 50 51 int v = i; 52 53 while(vis[v] != i && idx[v] == -1 && v != root) { 54 vis[v] = i; 55 v = pre[v]; 56 } 57 if(v != root && idx[v] == -1) { 58 for(int u = pre[v]; u != v; u = pre[u]) 59 idx[u] = cnt; 60 idx[v] = cnt ++; 61 } 62 } 63 if(cnt == 0) break; 64 for(int i = 0; i < V; ++ i) { 65 if(idx[i] == -1) 66 idx[i] = cnt ++; 67 } 68 69 for(int i = 0; i < E; ++ i) { 70 int v = e[i].to; 71 72 e[i].from = idx[e[i].from]; 73 e[i].to = idx[e[i].to]; 74 if(e[i].from != e[i].to) { 75 e[i].dis -= in[v]; 76 } 77 } 78 V = cnt; 79 root = idx[root]; 80 } 81 82 return res; 83 } 84 85 86 int main() { 87 while(scanf("%d%d", &n, &m) != EOF) { 88 sum = 0; 89 for(int i = 0; i < m; ++ i) { 90 scanf("%d%d%lld", &e[i].from, &e[i].to, &e[i].dis); 91 e[i].from ++; e[i].to ++; 92 sum += e[i].dis; 93 } 94 sum ++; 95 for(int i = 1; i <= n; ++ i) { 96 e[i + m - 1].from = 0; 97 e[i + m - 1].to = i; 98 e[i + m - 1].dis = sum; 99 } 100 101 ll ans = zhuliuMST(0, n + 1, n + m); 102 103 if(ans == -1 || ans >= sum * 2) { 104 puts("impossible"); 105 } 106 else { 107 printf("%lld %d\n", ans - sum, rt - m); 108 } 109 puts(""); 110 } 111 112 return 0; 113 }
题目15:BZOJ 1977
严格次小生成树
用倍增维护最大值和次大值。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cstring> 6 #include <queue> 7 8 using namespace std; 9 10 const int N = 100000 + 5; 11 const int M = 300000 + 5; 12 typedef long long ll; 13 const ll inf = 100000000000LL; 14 15 int n, m, cnt; 16 int ufs[N], head[N], fa[N][18], depth[N]; 17 ll mx1[N][18], mx2[N][18], mst, delta = inf; 18 19 struct Edge { 20 int from, to; 21 ll dis; 22 bool flag; 23 bool operator < (const Edge &a) const { 24 return dis < a.dis; 25 } 26 }e[M]; 27 28 struct edge { 29 int from, to, next; 30 ll dis; 31 }edges[N<<1]; 32 33 void insert(int from, int to, ll dis) { 34 ++ cnt; 35 edges[cnt].from = from; 36 edges[cnt].to = to; 37 edges[cnt].dis = dis; 38 edges[cnt].next = head[from]; 39 head[from] = cnt; 40 } 41 42 int find(int x) { 43 return ufs[x] == x ? x : (ufs[x] = find(ufs[x])); 44 } 45 46 void kruscal() { 47 int have = 0; 48 49 sort(e + 1, e + m + 1); 50 for(int i = 1; i <= n; ++ i) ufs[i] = i; 51 for(int i = 1; i <= m; ++ i) { 52 int fx = find(e[i].from), fy = find(e[i].to); 53 54 if(fx != fy) { 55 ufs[fx] = fy; 56 ++ have; 57 mst += e[i].dis; 58 e[i].flag = true; 59 insert(e[i].from, e[i].to, e[i].dis); 60 insert(e[i].to, e[i].from, e[i].dis); 61 if(have == n - 1) break; 62 } 63 } 64 } 65 66 void prepare() { 67 for(int j = 1; (1<<j) <= n; ++ j) { 68 for(int i = 1; i <= n; ++ i) { 69 if(fa[i][j - 1] != -1) { 70 fa[i][j] = fa[fa[i][j - 1]][j - 1]; 71 mx1[i][j] = max(mx1[i][j - 1], mx1[fa[i][j - 1]][j - 1]); 72 if(mx1[i][j - 1] == mx1[fa[i][j - 1]][j - 1]) { 73 mx2[i][j] = max(mx2[i][j - 1], mx2[fa[i][j - 1]][j - 1]); 74 } 75 else { 76 mx2[i][j] = min(mx1[i][j - 1], mx1[fa[i][j - 1]][j - 1]); 77 mx2[i][j] = max(mx2[i][j - 1], mx2[i][j]); 78 mx2[i][j] = max(mx2[i][j], mx2[fa[i][j - 1]][j - 1]); 79 } 80 } 81 } 82 } 83 } 84 85 void bfs() { 86 queue <int> q; 87 88 memset(fa, -1, sizeof fa); 89 q.push(1); depth[1] = 1; 90 fa[1][0] = 0; 91 while(!q.empty()) { 92 int x = q.front(); q.pop(); 93 94 for(int i = head[x]; i; i = edges[i].next) { 95 int v = edges[i].to; 96 97 if(!depth[v]) { 98 depth[v] = depth[x] + 1; 99 fa[v][0] = x; 100 mx1[v][0] = edges[i].dis; 101 q.push(v); 102 } 103 } 104 } 105 } 106 107 int lca(int a, int b) { 108 int i; 109 110 if(depth[a] < depth[b]) 111 swap(a, b); 112 for(i = 0; (1<<i) <= n; ++ i); 113 -- i; 114 for(int j = i; j >= 0; -- j){ 115 if(depth[a] - depth[b] >= (1<<j)) { 116 a = fa[a][j]; 117 } 118 } 119 if(a == b) return a; 120 for(int j = i; j >= 0; -- j) { 121 if(fa[a][j] != -1 && fa[a][j] != fa[b][j]) { 122 a = fa[a][j]; b = fa[b][j]; 123 } 124 } 125 return fa[a][0]; 126 } 127 128 void calc(int x, int f, ll nowedgev) { 129 ll d1 = 0, d2 = 0; 130 int temp = depth[x] - depth[f]; 131 132 for(int i = 0; (1<<i) <= n; ++ i) { 133 if(temp & (1<<i)) { 134 if(mx1[x][i] > d1) { 135 d2 = d1; 136 d1 = mx1[x][i]; 137 } 138 d2 = max(d2, mx2[x][i]); 139 x = fa[x][i]; 140 } 141 } 142 if(d1 != nowedgev) delta = min(delta, nowedgev - d1); 143 else delta = min(delta, nowedgev - d2); 144 } 145 146 void solve(int nowe) { 147 int x = e[nowe].from, y = e[nowe].to, f = lca(x, y); 148 ll vs = e[nowe].dis; 149 calc(x, f, vs); calc(y, f, vs); 150 } 151 152 int main() { 153 scanf("%d%d", &n, &m); 154 for(int i = 1; i <= m; ++ i) { 155 scanf("%d%d%lld", &e[i].from, &e[i].to, &e[i].dis); 156 } 157 kruscal(); 158 bfs(); 159 prepare(); 160 for(int i = 1; i <= m; ++ i) { 161 if(!e[i].flag) { 162 solve(i); 163 } 164 } 165 printf("%lld\n", mst + delta); 166 return 0; 167 }