A 国有 n 座城市,编号从 1 到 n ,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
思路
这题思路想明白了就很简单,一句话题意:求树上两点间路线中边长最小的边权。
首先,为什么是树呢?限重肯定越大越好,因此我们可以跑出图的最大生成树(Kruskal)
之后,我们就可以对于每次询问来求出路径上的最小边权(最多能运的货物重量),这里可以用到树上倍增法(求LCA时一起求了,虽然LCA不会直接用到,但也是要一起求出来的)
至于两点间是否能互达,就可以用并查集维护一下就行了!
实现
提交记录过于真实,从0到10到65到70到95到AC Orz
可能是我常数写丑了,所以在洛谷更新评测姬前以及不开氧气优化都会T两个点??
code
1 // luogu-judger-enable-o2 2 #include<cstdio> 3 #include<algorithm> 4 5 using namespace std; 6 7 int n,m,Q,tot; 8 int head[10090],vis[10090],fa[10090],d[10090]; 9 int f[10090][16],g[10090][16]; 10 struct Chemist{ 11 int f,t,w; 12 }qwq[50090]; 13 struct node{ 14 int next,to,val; 15 }edge[100090]; 16 17 bool cmp(Chemist A,Chemist B) 18 { 19 return A.w>B.w; 20 } 21 22 void add(int x,int y,int z) 23 { 24 edge[++tot].to=y; 25 edge[tot].val=z; 26 edge[tot].next=head[x]; 27 head[x]=tot; 28 } 29 30 int getf(int x) 31 { 32 if(fa[x]==x) return x; 33 else return getf(fa[x]); 34 } 35 36 void dfs(int u) 37 { 38 vis[u]=1; 39 for(int i=head[u];i;i=edge[i].next) 40 { 41 int v=edge[i].to; 42 if(!vis[v]) 43 { 44 f[v][0]=u; 45 g[v][0]=edge[i].val; 46 d[v]=d[u]+1; 47 dfs(v); 48 } 49 } 50 } 51 52 void Kruskal() 53 { 54 for(int i=1;i<=n;i++) 55 fa[i]=i; 56 sort(qwq+1,qwq+1+m,cmp); 57 for(int i=1;i<=m;i++) 58 { 59 int pp=getf(qwq[i].f); 60 int qq=getf(qwq[i].t); 61 if(pp!=qq) 62 { 63 fa[qq]=pp;//f[pp]=qq; 64 add(qwq[i].f,qwq[i].t,qwq[i].w); 65 add(qwq[i].t,qwq[i].f,qwq[i].w); 66 } 67 } 68 //连一条虚边 69 for(int i=1;i<=n;i++) 70 if(getf(i)!=getf(1)) add(1,i,0); 71 } 72 73 int lca(int x,int y) 74 { 75 int tmp=1e9; 76 if(d[x]<d[y]) swap(x,y); 77 for(int j=0;j<=13;j++) 78 if((1<<j)&(d[x]-d[y])) 79 { 80 tmp=min(tmp,g[x][j]); 81 x=f[x][j]; 82 } 83 if(x==y) return tmp; 84 for(int j=14;j>=0;j--) 85 if(f[x][j]!=f[y][j]) 86 { 87 tmp=min(tmp,g[x][j]); 88 tmp=min(tmp,g[y][j]); 89 x=f[x][j]; 90 y=f[y][j]; 91 } 92 tmp=min(tmp,g[x][0]); 93 tmp=min(tmp,g[y][0]); 94 return tmp; 95 } 96 97 int main() 98 { 99 scanf("%d%d",&n,&m); 100 for(int i=1;i<=m;i++) 101 scanf("%d%d%d",&qwq[i].f,&qwq[i].t,&qwq[i].w); 102 Kruskal(); 103 dfs(1);//树上倍增的准备工作 104 for(int j=1;j<=14;j++) 105 for(int i=1;i<=n;i++) 106 { 107 f[i][j]=f[f[i][j-1]][j-1]; 108 g[i][j]=min(g[i][j-1],g[f[i][j-1]][j-1]); 109 } 110 scanf("%d",&Q); 111 while(Q--) 112 { 113 int l=0,r=0,ans=0; 114 scanf("%d%d",&l,&r); 115 ans=lca(l,r); 116 if(ans==0) printf("-1\n"); 117 else printf("%d\n",ans); 118 } 119 return 0; 120 }
原文:https://www.cnblogs.com/nopartyfoucaodong/p/9504852.html