[2017浙工大之江学院决赛 H] qwb与学姐(并查集,按秩合并,最小生成树,LCA)
题目链接:http://115.231.222.240:8081/JudgeOnline/problem.php?cid=1005&pid=7
题意:中文题面。
手动画一下会发现所求边必然存在于最大生成树上,那么就可以首先构造一棵最大生成树。
问题转化成一棵树上求两个点之间的链上的最短边,用倍增lca就可以做了,但是我不会。
于是可以考虑建树时的操作,在求最大生成树的时候按秩合并,即集合大的根要做集合小的根的父亲,这样连一条有向边。因为最大声成树是从大到小遍历的,所以能保证点与点相连的链上的最短的那条边一直被更新着,并且能够维持整棵树高不会超过log(n)。
然后dfs预处理一下,查询的时候求lca,每次维护最短的边即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 typedef struct Edge { 6 int u, v, w, next; 7 }Edge; 8 const int maxn = 50500; 9 const int maxm = 200200; 10 int h1[maxn], h2[maxn], pre[maxn], rk[maxn]; 11 int n, m, q, ecnt1, ecnt2; 12 int depth[maxn], dis[maxn]; 13 Edge e[maxm<<1], ee[maxn<<1]; 14 15 void init() { 16 for(int i = 1; i <= n; i++) pre[i] = i; 17 memset(h1, -1, sizeof(h1)); 18 memset(h2, -1, sizeof(h2)); 19 memset(rk, 0, sizeof(rk)); 20 memset(depth, 0, sizeof(depth)); 21 memset(dis, 0, sizeof(dis)); 22 ecnt1 = ecnt2 = 0; 23 } 24 25 void a1(int u, int v, int w) { 26 e[ecnt1].u = u, e[ecnt1].v = v, e[ecnt1].w = w; 27 e[ecnt1].next = h1[u], h1[u] = ecnt1++; 28 } 29 30 void a2(int u, int v, int w) { 31 ee[ecnt2].u = u, ee[ecnt2].v = v, ee[ecnt2].w = w; 32 ee[ecnt2].next = h2[u], h2[u] = ecnt2++; 33 } 34 35 bool cmp(Edge a, Edge b) { return a.w > b.w; } 36 int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } 37 38 int unite(int x, int y, int w) { 39 x = find(x); y = find(y); 40 if(x != y) { 41 if(rk[x] >= rk[y]) { 42 if(rk[x] == rk[y]) rk[x]++; 43 pre[y] = x, a2(x, y, w); 44 } 45 else pre[x] = y, a2(y, x, w); 46 return 1; 47 } 48 return 0; 49 } 50 51 void dfs(int u, int p) { 52 for(int i = h2[u]; ~i; i=ee[i].next) { 53 int v = ee[i].v, w = ee[i].w; 54 if(p == v) continue; 55 depth[v] = depth[u] + 1; 56 dis[v] = w; pre[v] = u; 57 dfs(v, u); 58 } 59 } 60 61 int query(int u, int v) { 62 int ret = 0x7f7f7f7f; 63 if(depth[u] < depth[v]) swap(u, v); 64 while(depth[u] > depth[v]) { 65 ret = min(ret, dis[u]); 66 u = pre[u]; 67 } 68 while(u != v) { 69 ret = min(ret, min(dis[u], dis[v])); 70 u = pre[u]; v = pre[v]; 71 } 72 return ret; 73 } 74 75 int main() { 76 // freopen("in", "r", stdin); 77 int u, v, w; 78 while(~scanf("%d%d%d",&n,&m,&q)) { 79 init(); 80 for(int i = 0; i < m; i++) { 81 scanf("%d%d%d",&u,&v,&w); 82 a1(u, v, w); a1(v, u, w); 83 } 84 sort(e, e+ecnt1, cmp); 85 int mst = 0; 86 for(int i = 0; i < ecnt1; i++) { 87 u = e[i].u; v = e[i].v; w = e[i].w; 88 if(unite(u, v, w)) mst += w; 89 } 90 int rt = find(1); 91 memset(pre, -1, sizeof(pre)); 92 depth[rt] = 1; 93 dfs(rt, 0); 94 while(q--) { 95 scanf("%d%d",&u,&v); 96 printf("%d\n", query(u, v)); 97 } 98 } 99 return 0; 100 }