[NOIP2013]货车运输 D1 T3 最大生成树 LCA及其维护

11 篇文章 0 订阅
4 篇文章 0 订阅

好久不见同志们 现在我更新一发题解

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

下面是一张图
然后是多次询问

My solution

首先,本题需要一个简单的判断,那就是我们需要任意两点间的距离尽可能的大
其次,两点之间的路径只需要一次就可以
这意味着什么呢

我们其实只需要建立一棵树,当然是最大生成树
其次 我们可以找到树上的两个点之间的路径上的最小值
暴力的跑图绝对不是一个好的想法
这意味着我们需要一个lca维护,即分别求出两个点到lca之间的路径的最小值 然后取min即可

本题还有一个附加的问题 就是两点之间的连通性,当然,这个实在是太简单了。。做完kruskral就已经维护出来了,只需要find(x)就行了

那好 我们就说到这里
下面是代码
偶对了  我提前说一下,我已经把我的建图部分改成无向边的了
额 还有

无向边M开二倍

无向边M开二倍

无向边M开二倍

重要的事情说三遍

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 100000+5
#define M 1000000+5
#define inf 0x7fffffff
int f[N],fa[N][17],deep[N],d[N][17],n,m, head[N];
bool vis[N];
inline int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
struct graph
{
    int next, to, val;
    graph() {}
    graph(int _next, int _to, int _val)
    : next(_next), to(_to), val(_val) {}
} edge[M];
inline void add(int x, int y, int z)
{
    static int cnt = 0;
    edge[++cnt] = graph(head[x], y, z);
    head[x] = cnt;
    swap(x,y);
    edge[++cnt] = graph(head[x], y, z);
    head[x] = cnt;
}
struct node
{
    int from,to,val;
    bool operator < (const node &z)const
    {
        return val>z.val;
    }
}a[M];
int find(int x)
{
    return f[x]^x?f[x]=find(f[x]):f[x];
}
void dfs(int x)
{
    vis[x]=1;
    for(int i=1;i<=16;i++)
    {
        if(deep[x]<(1<<i))break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
        d[x][i]=min(d[x][i-1],d[fa[x][i-1]][i-1]);
    }
    for(int i=head[x];i;i=edge[i].next)
    {
        if(vis[edge[i].to])
            continue;
        fa[edge[i].to][0]=x;
        d[edge[i].to][0]=edge[i].val;
        deep[edge[i].to]=deep[x]+1;
        dfs(edge[i].to);
    }
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    int t=deep[x]-deep[y];
    for(int i=0;i<=16;i++)
        if((1<<i)&t)
            x=fa[x][i];
    for(int i=16;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
        {x=fa[x][i];y=fa[y][i];}
    }
    if(x==y)return x;
    return fa[x][0];
}
int ask(int x,int f)
{
    int mn=inf;
    int t=deep[x]-deep[f];
    for(int i=0;i<=16;i++)
    {
        if(t&(1<<i))
        {
           mn=min(mn,d[x][i]);
           x=fa[x][i];
        }
    }
    return mn;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        f[i]=i;
    for(int i=1;i<=m;++i)
        a[i].from=read(),a[i].to=read(),a[i].val=read();
    sort(a+1,a+m+1);
    memset(d,127/3,sizeof d);
    for(int i=1;i<=m;++i)
    {
        int fx=a[i].from,fy=a[i].to;
        fx=find(fx),fy=find(fy);
        if(fx^fy)
        {
            add(fx,fy,a[i].val);f[fx]=fy;
        }
    }
    for(int i=1;i<=n;++i)
        if(!vis[i])
            dfs(i);
    int q=read();
    while(q--)
    {
        int tmp1=read(),tmp2=read();
        int fx=find(tmp1),fy=find(tmp2);
        if(fx ^ fy)
        {
            printf("-1\n");
            continue;
        }
        int t=lca(tmp1,tmp2);
        printf("%d\n",min(ask(tmp1,t),ask(tmp2,t)) );
    }
}

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值