生成树题目泛做(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 }
NOI 2014

 

题目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 }
WC 2006

 

题目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 }
POJ 3241

 

题目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 }
BZOJ 1601

 

题目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 }
BZOJ 1232

 

题目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 }
Uva 10369

 

题目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     }  
UVA 1395

 

题目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 }
BZOJ 1050

 

题目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 }
POJ 1679

 

题目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 }
HDU 4081

 

题目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 }
POJ 3164

 

题目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 }
HDU 2121

 

题目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 }
BZOJ 1977

 

转载于:https://www.cnblogs.com/sxprovence/p/5188744.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值