货车运输(最大生成树,LCA)

时间:2019-03-16 16:46:03   收藏:0   阅读:192

洛咕

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

分析:显然限重就是边权.构建出图的最大生成树,然后树上每个节点dfs预处理出f[v][0]和dis[v][0],分别表示节点v的\(2^0\)级祖先(即父节点)是谁以及它到父节点的距离;然后对于每一个询问,利用倍增思想在树上LCA.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
int n,m,Q;
int f[10005][21],dis[10005][21],visit[10005],deep[10005];
int tot,head[10005],nxt[20005],to[20005],w[20005],fa[10005];
struct EDGE{
    int from,to,w;
}e[50005];
inline void add(int a,int b,int c){
    tot++;nxt[tot]=head[a];head[a]=tot;to[tot]=b;w[tot]=c;
    tot++;nxt[tot]=head[b];head[b]=tot;to[tot]=a;w[tot]=c;
}
bool cmp(const EDGE &a,const EDGE &b){return a.w>b.w;}
inline int find(int x){
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
inline void kruskal(){
    int k=0;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int a=find(e[i].from),b=find(e[i].to);
        if(a!=b){
            add(a,b,e[i].w);
            fa[b]=a;
            k++;
            if(k==n-1)break;
        }
    }
    return;
}
void dfs(int u){
    visit[u]=1;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(visit[v])continue;
        deep[v]=deep[u]+1;
        f[v][0]=u;dis[v][0]=w[i];
        dfs(v);
    }
    return;
}
int lca(int x,int y){
    int ans=1e9;
    if(deep[x]<deep[y])swap(x,y);
    for(int i=20;i>=0;i--){
        if(deep[f[x][i]]>=deep[y]){
            ans=min(ans,dis[x][i]);//一定先更新ans,再让x,y往上跳,下面同理.
            x=f[x][i];
        }
    }
    if(x==y)return ans;
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            ans=min(ans,min(dis[x][i],dis[y][i]));
            x=f[x][i];y=f[y][i];
        }
    }
    ans=min(ans,min(dis[x][0],dis[y][0]));
    return ans;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        e[i].from=read();
        e[i].to=read();
        e[i].w=read();
    }
    kruskal();//构建最大生成树
    for(int i=1;i<=n;i++){
        if(visit[i])continue;
        deep[i]=1;
        dfs(i);
        f[i][0]=i;dis[i][0]=1e9;
    }//预处理,有些点不一定连通(即有可能是森林)
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
        }//LCA的预处理
    Q=read();
    while(Q--){
        int x=read(),y=read();
        if(find(x)!=find(y))puts("-1");
        else printf("%d\n",lca(x,y));
    }
    return 0;
}
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!