题目链接:货车运输
这道题其实思路很显然,就是最大生成树加倍增。
我们来顺着代码讲一遍。
我们先读入n和m
然后把所有边的权值设置为0
读入时,重复的边只取最大(很显然)
然后kruscal进行最大生成树,用G和H两个vector分别去保存边和权值
然后倍增即可。
具体看代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct edge{//边
int u,v,w;
};
int n,m;
int p[10005];//父节点(用于最大生成树)
edge e[50005];
int f[10005][21],deep[10005];//f表示节点u的k级祖先,deep是深度
int g[10005][21];//表示节点u到u的k级祖先上最小权值
int vis[10005]; //用于bfs
vector<int> G[10005],H[10005];//保存树的边和权值
//int fa[10005];
int ques;
int find(int xx){
return xx==p[xx]?xx:p[xx]=find(p[xx]);
}
int cmp(edge a,edge b){
return a.w>b.w;
}
void kruscal(){
sort(e,e+m,cmp);
for(int i=1;i<=n;i++){
p[i]=i;
}
for(int i=0;i<m;i++){
int xx=find(e[i].u),yy=find(e[i].v);
if(xx!=yy){
p[xx]=yy;
G[e[i].u].push_back(e[i].v);
G[e[i].v].push_back(e[i].u);
H[e[i].u].push_back(e[i].w);
H[e[i].v].push_back(e[i].w);
}
}
}
void bfs(){
memset(g,0x3f,sizeof(g));
memset(vis,0,sizeof(vis));
memset(f,-1,sizeof(f));
queue<int> q;
int cur=1;
deep[cur]=1;
q.push(cur);
vis[cur]=1;
// f[cur][0]=-1;
// fa[cur]=-1;
while(!q.empty()){
cur=q.front();
q.pop();
int len=G[cur].size();
for(int i=0;i<len;i++){
if(vis[G[cur][i]]==0){
q.push(G[cur][i]);
vis[G[cur][i]]=1;
deep[G[cur][i]]=deep[cur]+1;
f[G[cur][i]][0]=cur;
g[G[cur][i]][0]=H[cur][i];
}
}
}
}
void init(){
for(int k=0;k<20;k++){
for(int j=1;j<=n;j++){
if(f[j][k]!=-1){
f[j][k+1]=f[f[j][k]][k];
g[j][k+1]=min(g[j][k],g[f[j][k]][k]);
}
}
}
}
int ans;
int jump(int u,int step){
for(int k=0;k<21;k++){
if(step&(1<<k)){
ans=min(ans,g[u][k]);
u=f[u][k];
}
}
return u;
}
void lca(int u,int v){
ans=0x3f3f3f3f;
if(deep[u]<deep[v]){
swap(u,v);
}
u=jump(u,deep[u]-deep[v]);
for(int k=20;k>=0;k--){
if(f[u][k]!=f[v][k]){
ans=min(min(ans,g[u][k]),g[v][k]);
u=f[u][k];
v=f[v][k];
}
}
ans=u==v?ans:min(min(ans,g[u][0]),g[v][0]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
e[i].w=0;
}
for(int i=0;i<m;i++){
int ww;
scanf("%d%d%d",&e[i].u,&e[i].v,&ww);
e[i].w=max(e[i].w,ww);
}
kruscal();
bfs();
init();
scanf("%d",&ques);
while(ques--){
int u,v;
scanf("%d%d",&u,&v);
if(u>n||v>n){
printf("-1\n");
continue;
}
if(find(u)!=find(v)){
printf("-1\n");
continue;
}else{
lca(u,v);
if(ans<0x3f3f3f3f){
printf("%d\n",ans);
}else{
printf("-1\n");
}
}
}
return 0;
}