NOIP2013 货车运输 倍增

问题描述

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入描述

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出描述

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

题解:

首先易得货车可以通过的权值最小的道路一定是在这个图的最大生成树中的。所以先用kruskal算一下最大生成树,将这个最大生成树再存一个图,起点和重点的连通性可以通过并查集来判断。

然后在这个最大生成树上找这两个点的lca,找到这个两个点之间的最小值,就是货车的最大载货量。

#include<bits/stdc++.h>
using namespace std;
#define maxn 10005
#define inf 0x7ffffff 
int n,m,q,cnt;
int deep[maxn],f[maxn],fa[maxn][17],d[maxn][17];
bool vis[maxn];
struct edge{
    int u,v,w;
}e[50005];
int head[maxn];
struct node{
    int next,to,k;
}a[20001];
void insert(int u,int v,int w){
    cnt++;
    a[cnt].next=head[u];a[cnt].to=v;a[cnt].k=w;
    head[u]=cnt;
}
bool cmp(edge a,edge b){
    return a.w>b.w;
}
void dfs(int x){
    vis[x]=1;
    for(int i=1;i<=16;i++){
        if(deep[x]<(1<<i))break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
        d[x][i]=min(d[x][i-1],d[fa[x][i-1]][i-1]);
    }
    for(int i=head[x];i;i=a[i].next){
        int s=a[i].to;
        if(vis[s])continue;
        fa[s][0]=x;
        d[s][0]=a[i].k;
        deep[s]=deep[x]+1;
        dfs(s);
    }
}
int lca(int x,int y){
    if(deep[x]<deep[y])swap(x,y);
    int t=deep[x]-deep[y];
    for(int i=0;i<=16;i++)
    if((1<<i)&t)x=fa[x][i];
    for(int i=16;i>=0;i--){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];y=fa[y][i];
        }
    }
    if(x==y)return x;
    return fa[x][0];
}
int ask(int x,int f){
    int mn=inf;
    int t=deep[x]-deep[f];
    for(int i=0;i<=16;i++){
        if(t&(1<<i)){
            mn=min(mn,d[x][i]);
            x=fa[x][i];
        }
    }
    return mn;
}
int find(int x){
    if(x==f[x])return x;
    return f[x]=find(f[x]);
}
int main(){
    memset(d,127,sizeof d);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)f[i]=i;
    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);
    int tot=0;
    for(int i=1;i<=m;i++){
        int p=find(e[i].u),q=find(e[i].v);
        if(p!=q){
            f[p]=q;
            insert(e[i].u,e[i].v,e[i].w);insert(e[i].v,e[i].u,e[i].w);
            tot++;
            if(tot==n-1)break;
        }
    }
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if(find(x)!=find(y)){printf("-1
");continue;}
        else {
            int t=lca(x,y);
            printf("%d
",min(ask(x,t),ask(y,t)));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Elfish/p/7717324.html