[洛谷P1967] 货车运输

Description

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

Input

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

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

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

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

Output

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

Sample Input

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

Sample Output

3
-1
3

HINT

对于 (30%) 的数据,(0 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000)

对于 (60%) 的数据, (0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000)

对于 (100%) 的数据, (0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000)


题解

也是一道比较经典最小瓶颈树题目。

$Kruskal + lca倍增 $
贪心想法,边权由小向大加,用并查集维护连通性。然后一想发现这就是 (Kruskal)
感觉这题跟今年 (NOI d1t1) 有些像啊,那道说是什么 (Kruskal重构树) ……

顺便提一个结论:
其实最小生成树就是最小瓶颈树,这是可以证明滴~(想想 (Kruskal) 的贪心过程就可以明白)


代码

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 10005;

struct node{
    int v,len;
    node *next;
}pool[N*2],*h[N];
int cnt;
void addedge(int u,int v,int len){
    node *p=&pool[++cnt],*q=&pool[++cnt];
    p->v=v;p->next=h[u];h[u]=p;p->len=len;
    q->v=u;q->next=h[v];h[v]=q;q->len=len;
}

int n,m;
int f[N][15],fmin[N][15],dep[N];
void dfs(int u){
    int v;
    for(node *p=h[u];p;p=p->next)
        if(!dep[v=p->v]){
            dep[v]=dep[u]+1;
            f[v][0]=u; fmin[v][0]=p->len;
            for(int j=1;j<15;j++){
                f[v][j]=f[f[v][j-1]][j-1];
                fmin[v][j]=min(fmin[v][j-1],fmin[f[v][j-1]][j-1]);
            }
            dfs(v);
        }
}
int query(int x,int y){
    int ret=100005;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=14;i>=0;i--)
        if(dep[f[x][i]]>=dep[y]) ret=min(ret,fmin[x][i]),x=f[x][i];
    if(x==y) return ret;
    for(int i=14;i>=0;i--)
        if(f[x][i]!=f[y][i]){
            ret=min(ret,min(fmin[x][i],fmin[y][i]));
            x=f[x][i]; y=f[y][i];
        }
    ret=min(ret,min(fmin[x][0],fmin[y][0]));
    return ret;
}

struct edge{
    int x,y,z;
    bool operator < (const edge &b) const { return z>b.z; }
}ed[N*5];
int fa[N];
int getfa(int x) { return fa[x]==x ? x : fa[x]=getfa(fa[x]) ; }
void merge(int x,int y){
    x=getfa(x); y=getfa(y);
    fa[x]=y;
}

int main()
{
    int x,y,q;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++) scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
    
    sort(ed,ed+m);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=0;i<m;i++){
        if(getfa(ed[i].x)==getfa(ed[i].y)) continue;
        addedge(ed[i].x,ed[i].y,ed[i].z);
        merge(ed[i].x,ed[i].y);
    }
    
    for(int j=0;j<15;j++) fmin[0][j]=100005;
    for(int i=1;i<=n;i++){
        if(dep[i]) continue;
        for(int j=0;j<15;j++) fmin[i][j]=100005;
        dep[i]=1;
        dfs(i);
    }
    
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&x,&y);
        if(getfa(x)!=getfa(y)) printf("-1
");
        else printf("%d
",query(x,y));
    }
    
    return 0;
}
既然选择了远方,便只顾风雨兼程
原文地址:https://www.cnblogs.com/lindalee/p/9733447.html