Luogu P1967 【貨車運輸】題解
阿新 • • 發佈:2018-11-15
一看到這道題,就想到了某次小生成樹
- 一般對於無向圖且不是樹的情況,求路徑經過邊的最小(最大)值且不考慮路徑總長,通常考慮最小(最大)生成樹
由於求儘量通過邊,最大生成樹即可
很愉快的,問題轉換成了如何求樹上兩點間的邊權最小值。
- 對於樹上路徑問題,我們通常考慮倍增或樹剖
(但我太菜了,不會樹剖)所以就用倍增代替了
也就是kruskal(懶得打prim)+倍增lca 綜合時間複雜度 \(O\)(\(m\log n\))
碼風奇特的程式碼如下:
#include<cstdio> #include<algorithm> using namespace std; inline int Min(int a,int b) { return a<b?a:b; } inline void swap(int &a,int &b) { a^=b^=a^=b; } int n,m; int f[10005]; struct edge { int u,v,w; } e[100005]; struct tree { int u[100005],v[100005],w[100005]; int first[10005],next[100005]; int tot=0; int addedge(int a,int b,int c) { ++tot; u[tot]=a,v[tot]=b,w[tot]=c; next[tot]=first[a]; first[a]=tot; } } tr; int cmp(edge a,edge b) { return a.w>b.w; } int gf(int x) { if(x==f[x]) { return x; } f[x]=gf(f[x]); return f[x]; } void merge(int a,int b) { int fa=gf(a); int fb=gf(b); if(fa!=fb) { f[fb]=fa; } } void kruskal() { for(int i=1; i<=n; i++) { f[i]=i; } for(int i=1; i<=m; i++) { if(gf(e[i].u)!=gf(e[i].v)) { merge(e[i].u,e[i].v); tr.addedge(e[i].u,e[i].v,e[i].w); tr.addedge(e[i].v,e[i].u,e[i].w); } } } int p[10005][25]; int mp[10005][25]; int dep[10005]; int vis[10005]; void dfs(int x) { vis[x]=1; for(int i=tr.first[x]; i; i=tr.next[i]) { if(!vis[tr.v[i]]) { p[tr.v[i]][0]=x; mp[tr.v[i]][0]=tr.w[i]; dep[tr.v[i]]=dep[x]+1; dfs(tr.v[i]); } } } void init() { for(int i=1; i<=n; i++) { dfs(i); } for(int j=1; j<=20; j++) { for(int i=1; i<=n; i++) { p[i][j]=p[p[i][j-1]][j-1]; mp[i][j]=Min(mp[i][j-1],mp[p[i][j-1]][j-1]); } } } int lca(int a,int b) { if(dep[a]<dep[b]) { swap(a,b); } for(int i=20; i>=0; i--) { if(dep[a]-(1<<i)>=dep[b]) { a=p[a][i]; } } if(a==b) { return a; } for(int i=20; i>=0; i--) { if(p[a][i]!=p[b][i]) { a=p[a][i]; b=p[b][i]; } } return p[a][0]; } int work(int a,int b) { int l=lca(a,b); int ans=1<<30; if(a!=l) { for(int i=20; i>=0; i--) { if(dep[p[a][i]]>dep[l]) { ans=Min(ans,mp[a][i]); a=p[a][i]; } } ans=Min(ans,mp[a][0]); } if(b!=l) { for(int i=20; i>=0; i--) { if(dep[p[b][i]]>dep[l]) { ans=Min(ans,mp[b][i]); b=p[b][i]; } } ans=Min(ans,mp[b][0]); } return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); } sort(e+1,e+m+1,cmp); kruskal(); init(); int q; scanf("%d",&q); for(int i=1; i<=q; i++) { int a,b; scanf("%d%d",&a,&b); if(gf(a)!=gf(b)) { printf("-1\n"); continue; } printf("%d\n",work(a,b)); } return 0; }