• 洛谷 P1967 货车运输(克鲁斯卡尔重构树)


    题目描述

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

    输入输出格式

    输入格式:

    第一行有两个用一个空格隔开的整数n,m n,mn,m,表示 AAA 国有n nn 座城市和 mmm 条道路。

    接下来 mmm行每行3 3 3个整数 x,y,zx, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx x号城市到y y y号城市有一条限重为 zzz 的道路。注意: xxx 不等于 yyy,两座城市之间可能有多条道路

    接下来一行有一个整数 q,表示有 q 辆货车需要运货。

    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。

    输出格式:

    共有 qqq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出−1-11。

    输入输出样例

    输入样例#1: 复制
    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    输出样例#1: 复制
    3
    -1
    3

    说明

    对于 30%30\%30%的数据,0<n<1,000,0<m<10,000,0<q<1,0000 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000;

    对于 60%60\%60%的数据,0<n<1,000,0<m<50,000,0<q<1,0000 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000;

    对于 100%100\%100%的数据,0<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,0000 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0z100,000。

    题解:哦,这题是多么睿智啊,未来又可以多出一段梗了

    有一回对我说道,“你学过OI吗么?”我略略点一点头。他说,“学过OI,……我便考你一考。2013年提高组的D1T3,怎样写的?”

    我想,讨饭一样的人,也配考我么?便回过脸去,不再理会。

    孔乙己等了许久,很恳切的说道,“不能写罢?……我教给你,记着!这些题应该记着。将来打比赛的时候,贺题要用。”

    我暗想我和打模拟赛的水平还很远呢,而且我们比赛也从不将原题上账;又好笑,又不耐烦,懒懒的答他道,“谁要你教,不是最大生成树上跑跑倍增嘛?”

    孔乙己显出极高兴的样子,将两个指头的长指甲敲着键盘,点头说,“对呀对呀!……这道题有四样写法,你知道么?”

    我愈不耐烦了,努着嘴走远。孔乙己刚解了锁屏,想在电脑上写题,见我毫不热心,便又叹一口气,显出极惋惜的样子。

    反正原来的做法就是最大生成树上跑跑lca,过程中顺便记录一下答案(lca至少有四种求法,不接受任何反驳╭(╯^╰)╮)

    但我仔细一思索这题好像克鲁斯卡尔重构树也能做,大概做法就是建出一颗重构树以后输出询问两点之间的lca就可以啦

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    
    vector<int> g[60060];
    struct edge
    {
        int from,to,val;
    }e[50050];
    int fa[100010],n,m,cnt,v[100010],deep[100010],f[100010][18];
    
    int cmp(edge x,edge y)
    {
        return x.val>y.val;
    }
    
    int init()
    {
        for(int i=1;i<=100000;i++)
        {
            fa[i]=i;
        }
    }
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    
    int union_(int x,int y,int val)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx==fy) return 0;
        fa[fx]=fa[fy]=++cnt;
        g[fx].push_back(cnt);
        g[cnt].push_back(fx);
        g[fy].push_back(cnt);
        g[cnt].push_back(fy);
        v[cnt]=val;
    }
    
    int dfs(int now,int fat,int dep)
    {
        f[now][0]=fat;
        deep[now]=dep;
        for(int i=1;i<=17;i++) f[now][i]=f[f[now][i-1]][i-1];
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i]==fat) continue;
            dfs(g[now][i],now,dep+1);
        }
    }
    
    int lca(int x,int y)
    {
        if(deep[x]<deep[y]) swap(x,y);
        for(int i=17;i>=0;i--) if(deep[f[x][i]]>=deep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=17;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    
    int main()
    {
        init();
        int from,to;
        scanf("%d%d",&n,&m);
        cnt=n;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].val);
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            union_(e[i].from,e[i].to,e[i].val);
        }
        for(int i=1;i<=cnt;i++)
        {
            if(find(i)==i) dfs(i,0,1);
        }
        int ttt;
        scanf("%d",&ttt);
        while(ttt--)
        {
            scanf("%d%d",&from,&to);
            int anc=lca(from,to);
            if(anc) printf("%d
    ",v[anc]);
            else  puts("-1");
        }
    }
  • 相关阅读:
    VMWARE虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本。 模块“Upgrade”启动失败。 未能启动虚拟机。
    常见Dos命令
    Javatest
    Java多线程
    idea/eclipse 常用快捷键
    单例模式
    x865中断和异常
    x866特权级
    x867页式管理(Paging)
    x864任务(task)
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9668548.html
Copyright © 2020-2023  润新知