BZOJ1977: [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3514 Solved: 941
[Submit][Status][Discuss]
Description
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
Input
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
Output
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
Sample Input
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
Sample Output
11
HINT
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
Source
【题解】
非严格次小生成树:求得MST,枚举加哪一条边,删除环上的最大边。
严格次小生成树:若最大边 = 加入的边,那么找不等于最大边的次大边
很多细节,见代码
求一条路径上最大边次大边时,用lca把他们拆成两条链求,更方便
由于INF设小了WA了一发
由于忘记在链上蹦跶了,WA了两发
我的AC记录啊。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <string> 10 #include <cmath> 11 #define min(a, b) ((a) < (b) ? (a) : (b)) 12 #define max(a, b) ((a) > (b) ? (a) : (b)) 13 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 14 template<class T> 15 inline void swap(T &a, T &b) 16 { 17 T tmp = a;a = b;b = tmp; 18 } 19 inline void read(long long &x) 20 { 21 x = 0;char ch = getchar(), c = ch; 22 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 23 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 24 if(c == '-') x = -x; 25 } 26 27 const long long INF = 0x3f3f3f3f3f3f3f3f; 28 const long long MAXN = 500000 + 10; 29 const long long MAXM = 500000 + 10; 30 31 long long u[MAXM],v[MAXM],w[MAXM],cnt[MAXM],n,m,fa[MAXN],tot,f1,f2,M,vis[MAXM]; 32 long long cmp(long long a, long long b) 33 { 34 return w[a] < w[b]; 35 } 36 long long find(long long x) 37 { 38 return x == fa[x] ? x : fa[x] = find(fa[x]); 39 } 40 struct Edge 41 { 42 long long u,v,w,nxt; 43 Edge(long long _u, long long _v, long long _w, long long _nxt){u = _u;v = _v;w = _w;nxt = _nxt;} 44 Edge(){} 45 }edge[MAXN << 1]; 46 long long head[MAXN], cntt; 47 inline void insert(long long a, long long b, long long c) 48 { 49 edge[++ cntt] = Edge(a,b,c,head[a]); 50 head[a] = cntt; 51 } 52 53 //p[0]表示跳到哪个节点,p[1]表示最大值,p[2]表示次大值 54 long long p[3][30][MAXN], deep[MAXN]; 55 void dfs(long long x, long long pre) 56 { 57 for(long long pos = head[x];pos;pos = edge[pos].nxt) 58 { 59 long long v = edge[pos].v; 60 if(v == pre) continue; 61 p[0][0][v] = x, p[1][0][v] = edge[pos].w;deep[v] = deep[x] + 1, dfs(v, x); 62 } 63 } 64 void yuchuli() 65 { 66 memset(p[1], -1, sizeof(p[1])); 67 memset(p[2], -1, sizeof(p[2])); 68 dfs(1, -1); 69 for(M = 0;(1 << M) <= n;++ M); -- M; 70 for(long long i = 1;i <= M;++ i) 71 for(long long j = 1;j <= n;++ j) 72 p[0][i][j] = p[0][i - 1][p[0][i - 1][j]]; 73 for(long long i = 1;i <= M;++ i) 74 for(long long j = 1;j <= n;++ j) 75 if(deep[j] >= (1 << i)) 76 { 77 long long tmp1 = p[1][i - 1][j], tmp2 = p[1][i - 1][p[0][i - 1][j]]; 78 if(tmp1 == tmp2) p[2][i][j] = max(p[2][i - 1][j], p[2][i - 1][p[0][i - 1][j]]), p[1][i][j] = tmp1; 79 else if(tmp1 > tmp2) p[2][i][j] = max(tmp2, p[2][i - 1][j]), p[1][i][j] = tmp1; 80 else p[2][i][j] = max(tmp1, p[2][i - 1][p[0][i - 1][j]]), p[1][i][j] = tmp2; 81 } 82 } 83 long long LCA(long long u, long long v) 84 { 85 if(deep[u] < deep[v]) swap(u, v); 86 for(long long i = M;i >= 0;-- i) 87 if(deep[u] >= deep[v] + (1 << i)) 88 u = p[0][i][u]; 89 if(u == v) return u; 90 for(long long i = M;i >= 0;-- i) 91 if(p[0][i][u] != p[0][i][v]) 92 u = p[0][i][u], v = p[0][i][v]; 93 return p[0][0][u]; 94 } 95 //v为lca 96 void lian(long long &ma, long long &cima, long long u, long long v) 97 { 98 ma = cima = -1; 99 for(long long i = M;i >= 0;-- i) 100 if(deep[u] >= deep[v] + (1 << i)) 101 { 102 if(ma < p[1][i][u]) cima = max(ma, p[2][i][u]), ma = p[1][i][u]; 103 else if(ma > p[1][i][u]) cima = max(cima, p[1][i][u]); 104 else cima = max(cima, p[2][i][u]); 105 u = p[0][i][u]; 106 } 107 } 108 109 void find(long long &ma, long long &cima, long long u, long long v) 110 { 111 long long lca = LCA(u, v); 112 long long lma, lcima, rma, rcima; 113 lian(lma, lcima, u, lca), lian(rma, rcima, v, lca); 114 ma = max(lma, rma); 115 if(lma > rma) cima = max(rma, lcima); 116 else if(lma < rma) cima = max(lma, rcima); 117 else cima = max(lcima, rcima); 118 } 119 120 long long ans, ans2; 121 int main() 122 { 123 read(n), read(m); 124 for(long long i = 1;i <= m;++ i) cnt[i] = i, read(u[i]), read(v[i]), read(w[i]); 125 for(long long i = 1;i <= n;++ i) fa[i] = i; 126 std::sort(cnt + 1, cnt + 1 + m, cmp); 127 for(long long i = 1;i <= m;++ i) 128 { 129 f1 = find(u[cnt[i]]), f2 = find(v[cnt[i]]); 130 if(f1 == f2) continue; 131 ++ tot;insert(u[cnt[i]], v[cnt[i]], w[cnt[i]]), insert(v[cnt[i]], u[cnt[i]], w[cnt[i]]); 132 fa[f1] = f2; vis[cnt[i]] = 1;ans += w[cnt[i]]; 133 if(tot == n - 1) break; 134 } 135 yuchuli();ans2 = INF; 136 for(long long i = 1;i <= m;++ i) 137 { 138 if(vis[i]) continue; 139 long long ma,cima; 140 find(ma, cima, u[i], v[i]); 141 if(w[i] != ma) ans2 = min(ans2, ans + (w[i] - ma)); 142 else ans2 = min(ans2, ans + (w[i] - cima)); 143 } 144 printf("%lld\n", ans2); 145 return 0; 146 }