[luogu1967]货车运输

Posted LJZ_C

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu1967]货车运输相关的知识,希望对你有一定的参考价值。

货车运输


Description

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

Input

输入文件名为 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 。

Output
-输出文件名为 truck.out。

输出共有 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,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。

题解

在最大生成树上树链剖分,用并查集判断是否可达

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

using namespace std;
typedef long long LL;

const int infty=1<<29;
int N,M,Q;
struct edge
{
    int to,nxt,cost;
}g[200050];
struct data
{
    int u,v,w;
}e[500050];
struct segmentnode
{
    int mn;
}seg[400050];
int ecnt,head[100050];
int bel[100050];
int vis[100050],val[100050];
int place;
int parent[100050],deep[100050],sz[100050],tid[100050],top[100050],rnk[100050];

inline void addedge(int u,int v,int w)
{
    g[ecnt]=(edge){v,head[u],w},head[u]=ecnt++;
    g[ecnt]=(edge){u,head[v],w},head[v]=ecnt++;
}

int comp(const data & a, const data & b){return a.w>b.w;}

int findset(int a){return a==bel[a]?a:bel[a]=findset(bel[a]);}

void kruskal()
{
    sort(e+1,e+M+1,comp);
    for(int i=1;i<=M;i++)bel[i]=i;
    for(int i=1;i<=M;i++)
    {
        int u=e[i].u,v=e[i].v,w=e[i].w;
        if(findset(u)==findset(v))continue;
        bel[findset(u)]=findset(v);
        addedge(u,v,w);
    }
}

void dfs(int root)
{
    vis[root] = 1;
    for(int i=head[root];~i;i=g[i].nxt)
    {
        int v=g[i].to;if(vis[v])continue;
        dfs(v);
    }
}

void getdeep(int root,int step,int fa)
{
    parent[root]=fa,deep[root]=step,sz[root]=1;
    for(int i=head[root];~i;i=g[i].nxt)
    {
        int v=g[i].to,w=g[i].cost;
        if(v == fa)continue;
        getdeep(v,step+1,root);
        sz[root]+=sz[v],val[v]=w;
    }
}

void devide(int root,int chain,int fa)
{
    top[root]=chain,tid[root]=++place,rnk[place]=root;
    int k=0;
    for(int i=head[root];~i;i=g[i].nxt)
    {
        int v=g[i].to;if(v==fa)continue;
        if(sz[v]>sz[k])k=v;
    }if(k==0)return;devide(k,chain,root);
    for(int i=head[root];~i;i=g[i].nxt)
    {
        int v=g[i].to;if(v==fa||v==k)continue;
        devide(v,v,root);
    }
}

inline void pushup(int root)
{
    seg[root].mn=min(seg[root<<1].mn,seg[root<<1|1].mn);
}

void build(int root,int l,int r)
{
    if(l==r){seg[root].mn=val[rnk[l]];return;}
    int mid=(l+r)>>1;
    build(root<<1,l,mid),build(root<<1|1,mid+1,r);
    pushup(root);
}

int getmin(int root,int l,int r,int a,int b)
{
    if(l==a&&r==b)return seg[root].mn;
    int mid=(l+r)>>1;
    if(b<=mid)return getmin(root<<1,l,mid,a,b);
    else if(a>mid)return getmin(root<<1|1,mid+1,r,a,b);
    else return min(getmin(root<<1,l,mid,a,mid),getmin(root<<1|1,mid+1,r,mid+1,b));
}

int getmin(int a,int b)
{
    int res=infty;
    while(top[a]!=top[b])
    {
        if(deep[top[a]]>deep[top[b]])swap(a,b);
        res=min(res,getmin(1,1,N+1,tid[top[b]],tid[b]));
        b=parent[top[b]];
    }if(deep[a]>deep[b])swap(a,b);
    if(a!=b)res=min(res,getmin(1,1,N+1,tid[a]+1,tid[b]));
    return res;
}

int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        memset(head,-1,sizeof(head));
        ecnt=place=0;
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        }
        kruskal();
        memset(vis,0,sizeof(vis));
        deep[N+1]=1;
        for(int i=1;i<=N;i++)
        {
            if(!vis[i])
            {
                addedge(N+1,i,infty);
                dfs(N+1);
            }
        }
        getdeep(N+1,1,0);
        devide(N+1,N+1,0);
        build(1,1,N+1);
        scanf("%d",&Q);
        for(int i=1,u,v;i<=Q;i++)
        {
            scanf("%d%d",&u,&v);
            if(findset(u)!=findset(v))
            {
                printf("-1\n");
                continue;
            }
            printf("%d\n",getmin(u,v));
        }
    }
    return 0;
}

以上是关于[luogu1967]货车运输的主要内容,如果未能解决你的问题,请参考以下文章

[luogu 1967]货车运输

[luogu P1967][NOIp2013]P1967 货车运输

Luogu-P1967 货车运输

Luogu P1967 货车运输

Luogu P1967 货车运输题解

luogu1967noip2013 货车运输 [生成树kruskal LCA ]