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