【Luogu】P1967货车运输(最大生成森林+倍增LCA)

  题目链接

  倍增LCA是个什么蛇皮原理啊,循环完了还得再往上跳一次才能到最近公共祖先

  合着我昨天WA两次就是因为这个

  建最大生成森林,因为图不一定是联通的,所以不一定是一棵树。这个地方用克鲁斯卡尔就好了

  然后给这个森林跑一遍DFS,顺便倍增

  然后对于每个询问跑LCA,倍增的时候已经顺便求出了最小边权,所以往上跳的同时更新答案。

  代码如下

#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

struct EDGE{
    int from,to,dis;
    bool operator <(const EDGE &a)const{
        return dis>a.dis;
    }
}que[1000010];

int father[100010];
struct Edge{
    int next,to,dis;
}edge[1000010];
int head[500010],num;
inline void add(int from,int to,int dis){
    edge[++num]=(Edge){head[from],to,dis};
    head[from]=num;
}

int find(int x){
    if(father[x]!=x)    father[x]=find(father[x]);
    return father[x];
}

inline void unionn(int x,int y){
    x=find(x);y=find(y);
    father[y]=x;
}

int deep[100010];
int d[10010][33];
int s[10010][33];

void dfs(int x,int fa){
    deep[x]=deep[fa]+1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        d[to][0]=x;
        s[to][0]=edge[i].dis;
        dfs(to,x);
    }
}
int cnt;
int main(){
    int n=read(),m=read();
    for(int i=1;i<=m;++i){
        int from=read(),to=read(),dis=read();
        que[i]=(EDGE){from,to,dis};
    }
    std::sort(que+1,que+m+1);
    for(int i=1;i<=n;++i)    father[i]=i;
    for(int i=1;i<=m;++i){
        int from=que[i].from,to=que[i].to,dis=que[i].dis;
        if(find(from)==find(to))    continue;
        unionn(from,to);
        add(from,to,dis);
        add(to,from,dis);
        if(++cnt==n-1)    break;
    }
    for(int i=1;i<=n;++i)
        if(!deep[i])    dfs(i,i);
    for(int j=1;(1<<j)<=n;++j)
        for(int i=1;i<=n;++i){
            d[i][j]=d[d[i][j-1]][j-1];
            s[i][j]=std::min(s[d[i][j-1]][j-1],s[i][j-1]);
        }
    int Q=read();
    for(int i=1;i<=Q;++i){
        int from=read(),to=read();
        if(find(from)!=find(to)){
            printf("-1\n");
            continue;
        }
        if(deep[from]<deep[to])    std::swap(from,to);
        int x=deep[from]-deep[to],ans=0x7fffffff;
        for(int j=0;(1<<j)<=x;++j)
            if((1<<j)&x){
                ans=std::min(ans,s[from][j]);
                from=d[from][j];
            }
        if(from==to){
            printf("%d\n",ans);
            continue;
        }
        for(int j=log2(n);j>=0;--j)
            if(d[from][j]!=d[to][j]){
                ans=std::min(ans,std::min(s[from][j],s[to][j]));
                from=d[from][j];
                to=d[to][j];
            }
        ans=std::min(ans,std::min(s[from][0],s[to][0]));
        printf("%d\n",ans);
    }
    return 0;
}

完毕。

时间: 2024-10-19 00:30:24

【Luogu】P1967货车运输(最大生成森林+倍增LCA)的相关文章

洛谷T1967 货车运输 Kruskal最大生成树&amp;&amp;倍增LCA

这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值.于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大.有了树之后,要求路径,那就要考虑LCA.首先,这题可以树剖,但是我太懒了,于是写了倍增233具体搞法:Kruskal跑出最大生成树,然后在树上倍增LCA,处理出2个数组:fa[][]和minv[][]:fa[][]表示第2^k个父亲是谁,minv[][]表示当前节点到其第2^k个父亲的路径上的最小边权.对于每次查询,在求LCA的同时,

luogu P1967 货车运输 最大生成树 倍增LCA

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 struct edg 7 { 8 int x,y,w; 9 friend bool operator < (edg x,edg y) 10 { 11 return x.w > y.w; 12 } 13 } vec[110000]; 1

Luogu P1967 货车运输

qwq 这题是知道了正解做法才写的.. 求每两点间最小权值最大的路径,本来我以为要每个点都跑一遍dij(?),后来意识到生成树好像是用来找这个的( ′▽`) 然后我问dtxdalao对不对,他说"我记得这道题好像要用倍增"(我:???剧透会被关进小黑屋的) 其实就是最大生成树是随便建的,然后对于每两点,用倍增求他们的lca,沿途更新最小的边权即为答案 其实我也没怎么debug (i--这种问题就不说了吧) 这题思路还算比较清晰,明白做法之后就分别把几个算法写出来就行了, 注意:lca中

P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

[luogu 1967]货车运输

货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条

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

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

洛谷 P1967 货车运输 Label: 倍增LCA &amp;&amp; 最小瓶颈路

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

CODEVS3287货车运输 noip2013day1T3(最大生成树+倍增)

题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路.接下来 m 行每行 3 个整数 x.y.z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路

洛谷 P1967 货车运输 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1967 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示