题目链接
https://www.luogu.org/problemnew/show/P1967
一眼看出思路,20分钟敲代码,40分钟调试
一个小时一次提交AC了这道题
首先有个结论
最大生成树上两两之间的路径一定是最大的,如果存在不是,那么这颗树就不是最大生成树
然后就树上倍增求最小边权就好了
然后以后根节点的父亲可以设为0,然后一开始跳到同一深度的时候特判一下就好了
然后注意一些细节,写在程序里面了
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int MAXN = 5e4 + 10; const int MAXM = 20; struct Edge{ int to, w, next; }; Edge e[MAXN << 1]; int head[MAXN], tot; int F[MAXN][MAXM + 5], data[MAXN][MAXM + 5]; //注意这里MAXM+5 int f[MAXN], vis[MAXN], d[MAXN], n, m; struct node { int u, v, w; bool operator < (const node& rhs) const { return w > rhs.w; } }; vector<node> edges; void AddEdge(int from, int to, int w) { e[tot] = Edge{to, w, head[from]}; head[from] = tot++; } void read(int& x) { int f = 1; x = 0; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } x *= f; } int find(int x) { if(f[x] == x) return x; return f[x] = find(f[x]); } void dfs(int u) { vis[u] = 1; for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(vis[v]) continue; //注意这里直接continue d[v] = d[u] + 1; //先算d再递归下去 dfs(v); F[v][0] = u; data[v][0] = e[i].w; } } int min_val(int u, int v) { int res = 1e9; if(d[u] < d[v]) swap(u, v); for(int j = MAXM; j >= 0; j--) if(F[u][j] && d[F[u][j]] >= d[v]) //注意这里要特判0 { res = min(res, data[u][j]); //注意这里一定是先统计再跳 u = F[u][j]; } if(u == v) return res; for(int j = MAXM; j >= 0; j--) if(F[u][j] != F[v][j]) { res = min(res, min(data[u][j], data[v][j])); u = F[u][j]; v = F[v][j]; } return min(res, min(data[u][0], data[v][0])); } int main() { memset(head, -1, sizeof(head)); tot = 0; read(n); read(m); _for(i, 1, m) { int u, v, w; read(u); read(v), read(w); edges.push_back(node{u, v, w}); } sort(edges.begin(), edges.end()); _for(i, 1, n) f[i] = i; REP(i, 0, edges.size()) { int u = edges[i].u, v = edges[i].v, w = edges[i].w; int fu = find(u), fv = find(v); if(fu != fv) { f[fu] = fv; AddEdge(u, v, w); AddEdge(v, u, w); } } _for(u, 1, n) if(!vis[u]) { F[u][0] = 0; //这里把每个根的父亲设为0,在倍增的时候需要特判0 dfs(u); } _for(j, 1, MAXM) _for(u, 1, n) { F[u][j] = F[F[u][j-1]][j-1]; data[u][j] = min(data[u][j-1], data[F[u][j-1]][j-1]); } int q; read(q); while(q--) { int u, v; read(u); read(v); if(find(u) != find(v)) puts("-1"); else printf("%d\n", min_val(u, v)); } return 0; }