Luogu P1967 【货车运输】题解
一看到这道题,就想到了某次小生成树
- 一般对于无向图且不是树的情况,求路径经过边的最小(最大)值且不考虑路径总长,通常考虑最小(最大)生成树
由于求尽量通过边,最大生成树即可
很愉快的,问题转换成了如何求树上两点间的边权最小值。
- 对于树上路径问题,我们通常考虑倍增或树剖
(但我太菜了,不会树剖)所以就用倍增代替了
也就是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;
}