[NOIP2013]货车运输 D1 T3

题目传送门

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

数据范围:

对于 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。

题目分析:

今天自己讲完LCA后对LCA有了较深的理解 所以就找题来做啦

想要货车要运尽可能多的货,就应该尽可能走承受力较大的路。
因此如果这两个点联通,货车一定是在这些点构成的最大生成树上行走更优。
于是问题抽象为:n个点m条边的一个无向有权图(其实是许多树构成的森林)
求任意两个点之间的最短路径上权值最小的那条边的权值。

先使用kruscal算法得到由最大生成树构成的森林。
对于每一组询问,首先使用并查集看一下这两个点是否在一棵树上
不在的话直接输出-1,如果在,就使用倍增LCA算法求出结果。

这里还要预处理出 点x到(点x的2^k的祖先)的路径中的最小值

sum[x][0]=val[to[i]];
sum[x][i]=min(sum[x][i-1],sum[fa[x][i-1]][i-1]);

在LCA过程中求出路径最小值即可

然而一开始设为sum[10011][20],fa[10011][20] 当temp=20时数组越界导致狂WA不止 下次一定要开到 30 QAQ

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct your
{
    int x,y,val;
}a[50010];
struct tree
{
    int next,to,val;
}b[100100];
int head[10010];
int fa[10011][21];
int deep[10010];
int sum[10011][21];
int f[10011];
bool book[10011];
int n,m;
int find(int x)
{
    return (f[x]==x)?x:f[x]=find(f[x]);
}
int tot;
void add(int x,int y,int v)
{
    b[++tot].next=head[x];
    b[tot].to=y;
    b[tot].val=v;
    head[x]=tot;
}
void klu()
{
    int ans=0;
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        int dx=find(a[i].x),dy=find(a[i].y);
        if(dx!=dy)
        {
            f[dx]=dy;
            add(a[i].x,a[i].y,a[i].val);
            add(a[i].y,a[i].x,a[i].val);
            cnt++;
            ans+=a[i].val;
        }
        if(cnt==n-1) return ;
    }
}
void dfs(int x,int temp)
{
    book[x]=true;
    fa[x][0]=temp;
    deep[x]=deep[temp]+1;
    for(int i=1;fa[x][i-1];i++)
    {
    	fa[x][i]=fa[fa[x][i-1]][i-1];
    	sum[x][i]=min(sum[x][i-1],sum[fa[x][i-1]][i-1]);
    }
    for(int i=head[x];i;i=b[i].next)
    {
        if(b[i].to==temp)continue;
        sum[b[i].to][0]=b[i].val;
        dfs(b[i].to,x);
    }
}
void Swp(int &x,int &y)
{
    int tmp=x;
    x=y;y=tmp;
    return;
}
int lca(int x,int y)
{
    int nmp=0x7f7f7f7f;
    if(deep[x]<deep[y]) Swp(x,y);
    int temp=20;
    while(temp>=0)
    {
        if(deep[fa[x][temp]]>=deep[y])
            nmp=min(nmp,sum[x][temp]),x=fa[x][temp];
        temp--;
    }
    if(x==y) return nmp;
    temp=20;
    while(temp>=0)
    {
        if(fa[x][temp]!=fa[y][temp])
        {
            nmp=min(nmp,sum[x][temp]);
            nmp=min(nmp,sum[y][temp]);
            x=fa[x][temp],y=fa[y][temp];
        }
        temp--;
    }
    nmp=min(sum[x][0],nmp);
    nmp=min(sum[y][0],nmp);
    return nmp;
}
void init()
{
    memset(sum,0x3f,sizeof sum);
    for(int i=1;i<=n;i++) f[i]=i;
}
bool cmp(your j,your k)
{
    return j.val>k.val;
}
int q;
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
    sort(a+1,a+m+1,cmp);
    klu();
    for(int i=1;i<=n;i++)
        if(!book[i])dfs(i,0);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int dx=find(x),dy=find(y);
        if(dx!=dy) printf("-1\n");
        else printf("%d\n",lca(x,y));
    }
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注