这题是知道了正解做法才写的..
求每两点间最小权值最大的路径,本来我以为要每个点都跑一遍dij(?),后来意识到生成树好像是用来找这个的( ´▽`)
然后我问dtxdalao对不对,他说“我记得这道题好像要用倍增”(我:???剧透会被关进小黑屋的)
其实就是最大生成树是随便建的,然后对于每两点,用倍增求他们的lca,沿途更新最小的边权即为答案
其实我也没怎么debug (i--这种问题就不说了吧)
这题思路还算比较清晰,明白做法之后就分别把几个算法写出来就行了,
注意:lca中最小边权的更新可能在跳到深度相同/同时倍增/最后求lca的路上,所以...反正多更新几次就没错啦w
#include<cstdio> #include<algorithm> #include<cmath> #define MogeKo qwq using namespace std; const int maxn = 100005; int n,m,q,x,y; int cnt,head[maxn],to[maxn],nxt[maxn],val[maxn]; int fa[maxn],dpth[maxn],p[maxn][25],w[maxn][25]; void add(int x,int y,int z) { to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; val[cnt] = z; } struct edg { int l,r,c; } a[maxn]; bool cmp(edg A,edg B) { return A.c > B.c; } int getfa(int x) { if(fa[x] == x)return x; else return fa[x] = getfa(fa[x]); } void kruskal() { sort(a+1,a+m+1,cmp); for(int i = 1; i <= m; i++) { int xx = getfa(a[i].l); int yy = getfa(a[i].r); if(xx == yy)continue; fa[xx] = yy; add(xx,yy,a[i].c); add(yy,xx,a[i].c); } } void dfs(int u,int fa) { for(int i = 1; (1 << i) <= dpth[u]; i++) { p[u][i] = p[p[u][i-1]][i-1]; w[u][i] = min(w[u][i-1],w[p[u][i-1]][i-1]); } for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; if(v == fa)continue; dpth[v] = dpth[u]+1; p[v][0] = u; w[v][0] = val[i]; dfs(v,u); } } int lca(int a,int b) { int ans = 2147483647; if(dpth[a] < dpth[b]) swap(a,b); for(int i = log2(dpth[a]); i >= 0; i--) if(dpth[p[a][i]] >= dpth[b]) { ans = min(ans,w[a][i]); a = p[a][i]; } if(a == b)return ans; for(int i = log2(dpth[a]); i >= 0; i--) if(p[a][i] != p[b][i]) { ans = min(ans,min(w[a][i],w[b][i])); a = p[a][i]; b = p[b][i]; } ans = min(ans,min(w[a][0],w[b][0])); return ans; } int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= m; i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].c); kruskal(); for(int i = 1; i <= n; i++) if(fa[i] == i){ dpth[i] = 1; dfs(i,0); } scanf("%d",&q); while(q--) { scanf("%d%d",&x,&y); int xx = getfa(x); int yy = getfa(y); if(xx != yy) { printf("-1 "); continue; } printf("%d ",lca(x,y)); } return 0; }