noip2013 货车运输

题目描述

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

输入输出格式

输入格式:

 

第一行有两个用一个空格隔开的整数n,mn,m,表示 AA 国有nn 座城市和 mm 条道路。

接下来 mm行每行33个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx号城市到yy号城市有一条限重为 zz 的道路。注意: xx 不等于 yy,两座城市之间可能有多条道路 。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y 。

 

输出格式:

 

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

 

根据题目得知,我们可以不用考虑路径有多长,只用考虑是否能到以及经过路径的最大值。

这样我们可以把原图化简为一个最大生成树,保证原图能到达的点,化简后也能到达。

然后对于每一个x、y,只用求出它们的路径中间的最小值就可以了。用LCA就行

但是!我们发现,输入的图不一定是联通的!也就是,我们生成的不一定是最大生成树而是最大生成森林!

这样,我们跑LCA会原地爆炸!

故此,我们可以在构建完最大森林后,将所有森林的根节点连到一个虚拟节点0,。

如果LCA时,发现两个的LCA是0,那么就输出-1.

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define in(a) a=read()
#define MAXN 500010
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m,p,ans;
int f[MAXN];
queue <int> Q;
int total=0,head[MAXN],to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
int vis[MAXN],depth[MAXN];
int tree[MAXN][30],minn[MAXN][30];
struct node{
    int a,b,c;
}l[MAXN];
inline bool cmp(node a,node b){
    return a.c>b.c;
}
inline int getf(int k){//并查集求最大生成森林
    if(f[k]==k)  return k;
    return f[k]=getf(f[k]);
}
inline void adl(int a,int b,int c){
    total++;
    to[total]=b;
    val[total]=c;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void bfs(){//LCA预处理
    Q.push(0);
    vis[0]=1;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        REP(i,1,18)
            tree[u][i]=tree[tree[u][i-1]][i-1],minn[u][i]=min(minn[u][i-1],minn[tree[u][i-1]][i-1]);
        for(int e=head[u];e;e=nxt[e])
            if(!vis[to[e]]){
                vis[to[e]]=1;
                depth[to[e]]=depth[u]+1;
                tree[to[e]][0]=u;
                minn[to[e]][0]=val[e];
                Q.push(to[e]);
            }
    }
    return ;
}
inline int lca(int u,int v){//跑LCA
    if(depth[u]<depth[v])  swap(u,v);
    int d=depth[u]-depth[v];
    REP(i,0,18)
        if(d&(1<<i)){
            ans=min(ans,minn[u][i]);
            u=tree[u][i];
        }
    if(u==v)  return u;
    for(int i=18;i>=0;i--)
        if(tree[u][i]!=tree[v][i]){
            ans=min(ans,min(minn[u][i],minn[v][i]));
            u=tree[u][i];
            v=tree[v][i];
        }
    ans=min(ans,min(minn[u][0],minn[v][0]));
    u=tree[u][0];
    v=tree[v][0];
    return u;
}
int main(){
    in(n);in(m);
    REP(i,1,n)  f[i]=i;
    REP(i,1,m)
      in(l[i].a),in(l[i].b),in(l[i].c);
    sort(l+1,l+m+1,cmp);
    REP(i,1,m){
        int f1=getf(l[i].a),f2=getf(l[i].b);
        if(f1!=f2){
            adl(l[i].a,l[i].b,l[i].c);
            adl(l[i].b,l[i].a,l[i].c);
            f[f2]=f1;
        }
    }
    REP(i,1,n)//构建虚拟节点
        if(!vis[i]){
            adl(0,i,0);
            bfs();//对于森林里的每一颗树都跑一边预处理
        }
    in(p);
    int u,v;
    REP(i,1,p){
        ans=2147483647;
        in(u),in(v);
        if(lca(u,v))  cout<<ans<<endl;
        else  cout<<"-1"<<endl;
    }
    return 0;
}
    

 

posted @ 2018-10-10 18:21  Dijkstra·Liu  阅读(394)  评论(0编辑  收藏  举报