邦德市

【问题描述】  

  邦德市有N(编号为1..N)个城市,用M条双向道路连接,每条道路都有一个危险系数。你的任务是回答若干询问,每个询问包含一个起点s和一个终点t,要求找到一条s到t的路径,使得路径上所有边的最大危险系数最小。

【输入格式】  

  第一行一个包含两个整数N和M;
  接下来的M行,每行包含三个整数:x,y,d(1<=x,y<=N0<=d<=1 000 000 000),即城市x于城市y有一条危险系数为d的双向道路。
下一行一个整数Q,表示有Q个询问;
  接下来的Q行,每行包含两个整数s,t(s!=t),表示一个询问的起点和终点。

【输出格式】  

  对于每个询问,输出最优路线上所有边的危险系数的最大值。(输入数据保证所有城市是连通的)。

【输入样例】  

4 5
1 2 10
1 3 20
1 4 100
2 4 30
3 4 10
2
1 4
4 1


【输出样例】  

20
20


【数据范围】  

对于30%的数据,满足1≤ n≤10001≤m≤100001≤q≤100; 
对于50%的数据,满足1≤ n≤100001≤m≤100001≤q≤10000; 
对于100%的数据,满足1≤ n≤100001≤m≤1000001≤q≤10000
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<iostream>
#define maxn 100005
#define inf 11111111111111111
using namespace std;
struct data
{
    int a,b,l;
};
int n,m,x,y,z,t;
long long oo=0,ans=inf;
int fa[maxn],ha[maxn],dep[maxn]={0},dist[maxn]={0};
vector<data>g;
vector<int>p[maxn],q[maxn];
bool vis[300005]={0};

void clear()        //清空 
{
    for(int i=1;i<=n;i++) fa[i]=ha[i]=i;
}
int find(int x)     //查找 
{
    if(fa[x]==x) return x;
    int t=find(fa[x]);
    fa[x]=t;
    return t;
}
void Union(int x,int y)     //合并 
{
    fa[find(x)]=find(y);
}
bool check(int x,int y)     //检查 
{
    return find(x)==find(y);
}

int getmax(int x,int y)
{
    int Max=0;
    if(dep[x]<dep[y]) swap(x,y); 

    while(dep[x]!=dep[y])
    {
        Max=max(Max,dist[x]-dist[fa[x]]);
        x=fa[x];    
    } 

    while(x!=y)
    {
        Max=max(Max,dist[x]-dist[fa[x]]);
        Max=max(Max,dist[y]-dist[fa[y]]);

        x=fa[x];
        y=fa[y];
    }

    return Max;
} 

bool cmp(data xx,data yy)
{
    return xx.l<yy.l;
} 

void task()     //算出最小生成树 
{
    for(int i=0;i<g.size();i++)
    {
        int u=g[i].a,v=g[i].b;
        if(check(u,v)) continue;
        Union(u,v);
        p[u].push_back(v);          //储存最小生成树的边 
        p[v].push_back(u);
        q[v].push_back(g[i].l);     //距离 
        q[u].push_back(g[i].l);
        vis[i]=true;
        oo=g[i].l;
    }
}

void fuck(int x,int y,int z)        //x,x的父亲,x的层数 
{
    fa[x]=y;
    dep[x]=z;
    for(int i=0;i<p[x].size();i++)
    {
        int j=p[x][i]; 
        if(j==y) continue;              
        dist[j]=dist[x]+q[x][i];
        fuck(j,x,z+1);              
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {   
        scanf("%d%d%d",&x,&y,&z);
        g.push_back((data){x,y,z}); 
    }
    sort(g.begin(),g.end(),cmp);
    clear();
    task();
    fuck(1,1,1);     //(1,1的父亲,层数) 

    scanf("%d",&t);

    while(t--)
    {
        scanf("%d%d",&x,&y);
        if(y>x) swap(x,y);
        int ans=getmax(x,y);
        printf("%d\n",ans);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值