[LCA]NEW![最小生成树]货车运输

题目描述

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。

输入输出样例

输入样例
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例
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。

分析

首先这题容易想到每个询问跑一边spfa什么的
然而TLE (Time Limit Enough滑稽)
然后发现,它并不需要最短路啊!只要点和点之间的路有一个最小值最大即可
容易想到最小最大生成树,用并查集优化
建完树以后,我们还是要花时间去遍历,怎么办呢?
想到神奇的LCA(最近公共祖先)因为是棵树嘛
这个LCA不只要求祖先,同时要用倍增求出一个值即到2^k的最小载重
然后-1用并查集判断即可

#include <iostream>
#include <cstdio>
#include <algorithm>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int n,m,q;
int f[10001],d[10001];
int z[10001][21],p[10001][21];
struct E1
{
    int u,v,z;
}b[100001];
int list[10001];
struct E2
{
    int u,v,z,next;
}a[100001];
int cnt;
bool cmp(E1 a,E1 b){return a.z>b.z;};
int getf(int x)
{
    if (f[x]==x) return x;
    return f[x]=getf(f[x]);
}
void add(int u,int v,int z)
{
    a[++cnt].u=u;a[cnt].v=v;a[cnt].z=z;a[cnt].next=list[u];list[u]=cnt;
}
void init()
{
    int i;
    scanf("%d%d",&n,&m);
    rep(i,1,m)
    scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].z);
    sort(b+1,b+m+1,cmp);
    rep(i,1,n)
    f[i]=i;
}
void kr()
{
    int i,fu,fv;
    rep(i,1,m)
    {
        fu=getf(b[i].u);fv=getf(b[i].v);
        if (fu!=fv)
        {
            f[fu]=fv;
            add(b[i].u,b[i].v,b[i].z);
            add(b[i].v,b[i].u,b[i].z);
        }
    }
}
void dfs(int x)
{
    int i;
    for (i=list[x];i;i=a[i].next)
    if (!d[a[i].v])
    {
        d[a[i].v]=d[x]+1;
        p[a[i].v][0]=x;
        z[a[i].v][0]=a[i].z;
        dfs(a[i].v);
    }
}
void power()
{
    int i,j; 
    rep(i,1,20)
    rep(j,1,n)
    {
        p[j][i]=p[p[j][i-1]][i-1];
        z[j][i]=min(z[j][i-1],z[p[j][i-1]][i-1]);
    }
}
void doit()
{
    int i;
    kr();
    rep(i,1,n)
    if (!d[i])
    {
        d[i]=1;
        dfs(i);
    }
    power();
}
int lca(int a,int b)
{
    int x=a,y=b,i,ans=2147483647;
    if (d[x]<d[y]) swap(x,y);
    for (i=20;i>=0;i--)
    if (d[p[x][i]]>=d[y])
    {
        ans=min(ans,z[x][i]);
        x=p[x][i];
    }
    if (x==y) return ans;
    for (i=20;i>=0;i--)
    if (p[x][i]!=p[y][i])
    {
        ans=min(ans,z[x][i]);
        ans=min(ans,z[y][i]);
        x=p[x][i];
        y=p[y][i];
    }
    ans=min(ans,z[y][0]);
    ans=min(ans,z[x][0]);
    return ans;
}
void print()
{
    int i,x,y,p;
    scanf("%d",&q);
    rep(i,1,q)
    {
        scanf("%d%d",&x,&y);
        if (getf(x)!=getf(y))
        printf("-1\n");
        else
        printf("%d\n",lca(x,y));
    }
}
int main()
{
    init();
    doit();
    print();
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/80024469
今日推荐