luogu1967 货车运输

30 篇文章 0 订阅
6 篇文章 0 订阅

http://www.elijahqi.win/archives/1021
题目描述

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

输入输出格式

输入格式:

输入文件名为 truck.in。

输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

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

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

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

输出格式:

输出文件名为 truck.out。

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

输入输出样例

输入样例#1:

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例#1:

3
-1
3
说明

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

对于 60%的数据,0 < 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,000。

这题是贪心 的找最大的边 大概期望复杂度是o(q*m)

复杂度肯定不满足 那么 考虑到prim是如何生成树的 我们想到用kruskal生成一棵最大生成树

然后去寻找树上路径的瓶颈 那么就可以考虑倍增做

然后求出最小值即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 11000
#define M 55000
using namespace std;
inline int read(){
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
struct node{
    int x,y,z,next;
}data[M],data1[N<<1];
int fa1[N],m,n,h[N],fa[N][20],st[N][20],dep[N],qq,Log[N];
inline bool cmp(node a,node b){return a.z>b.z;}
inline int find(int x){return x==fa1[x]?x:fa1[x]=find(fa1[x]);}
void dfs1(int x){
    for (int i=h[x];i;i=data1[i].next){
        int y=data1[i].y;
        if (fa[x][0]==y) continue;
        dep[y]=dep[x]+1;st[y][0]=data1[i].z;fa[y][0]=x;
        for (int j=1;j<=Log[dep[y]-1];++j){
            fa[y][j]=fa[fa[y][j-1]][j-1];st[y][j]=min(st[y][j-1],st[fa[y][j-1]][j-1]);
        }
        dfs1(y);
    }
}
inline int lca(int x,int y){
    int min1=0x7f7f7f7f;
    if (dep[x]!=dep[y]){
        if (dep[x]<dep[y]) swap(x,y);
        int lg=Log[dep[x]-dep[y]];
        for (int j=0;j<=lg;++j){
            if ((1<<j)&(dep[x]-dep[y])) {
                min1=min(min1,st[x][j]);x=fa[x][j];
            }
        }
    }
    if (x==y) return min1;
    for (int j=18;j>=0;--j){
        if (fa[x][j]!=fa[y][j]){
            min1=min(min1,st[x][j]);min1=min(min1,st[y][j]);x=fa[x][j];y=fa[y][j];
        }
    }
    return min(min1,min(st[x][0],st[y][0]));
}
int main(){
    freopen("truck.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<=m;++i){
        int x=read(),y=read(),z=read();
        data[i].x=x;data[i].y=y;data[i].z=z;
    }
    sort(data+1,data+m+1,cmp);
    for (int i=1;i<=n;++i) fa1[i]=i;int cnt=0,num=0;
    for (int i=1;i<=m;++i){
        int x=data[i].x,y=data[i].y,z=data[i].z;
        int xx=find(x),yy=find(y);
        if (xx!=yy){
            ++cnt;data1[++num].y=y;data1[num].z=data[i].z;data1[num].next=h[x];h[x]=num;data1[num].x=x;
            data1[++num].y=x;data1[num].z=data[i].z;data1[num].next=h[y];h[y]=num;fa1[xx]=yy;data1[num].x=y;
            if (cnt==n-1) break;
        }
    }   //for (int i=1;i<=num;++i) printf("%d %d %d\n",data1[i].x,data1[i].y,data1[i].z);printf("asdfasd\n");
    Log[0]=-1;
    for (int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
    for (int i=1;i<=n;++i) {
        if (fa1[i]==i) {
            dep[i]=1;dfs1(i);
        }
    }
//  for (int i=1;i<=n;++i) printf("%d ",st[i][0]);printf("\n");
//  for (int i=1;i<=n;++i) printf("%d ",fa[i][0]);printf("\n");
//  printf("%d \n",st[4][2]);
    qq=read();
    for (int i=1;i<=qq;++i){
        int x=read(),y=read();
        if (find(x)!=find(y)) {
            printf("-1\n");continue;
        }
        printf("%d\n",lca(x,y));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值