货车运输(最大生成树,LCA)

洛咕

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

分析:显然限重就是边权.构建出图的最大生成树,然后树上每个节点dfs预处理出f[v][0]和dis[v][0],分别表示节点v的\(2^0\)级祖先(即父节点)是谁以及它到父节点的距离;然后对于每一个询问,利用倍增思想在树上LCA.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
int n,m,Q;
int f[10005][21],dis[10005][21],visit[10005],deep[10005];
int tot,head[10005],nxt[20005],to[20005],w[20005],fa[10005];
struct EDGE{
    int from,to,w;
}e[50005];
inline void add(int a,int b,int c){
    tot++;nxt[tot]=head[a];head[a]=tot;to[tot]=b;w[tot]=c;
    tot++;nxt[tot]=head[b];head[b]=tot;to[tot]=a;w[tot]=c;
}
bool cmp(const EDGE &a,const EDGE &b){return a.w>b.w;}
inline int find(int x){
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
inline void kruskal(){
    int k=0;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int a=find(e[i].from),b=find(e[i].to);
        if(a!=b){
            add(a,b,e[i].w);
            fa[b]=a;
            k++;
            if(k==n-1)break;
        }
    }
    return;
}
void dfs(int u){
    visit[u]=1;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(visit[v])continue;
        deep[v]=deep[u]+1;
        f[v][0]=u;dis[v][0]=w[i];
        dfs(v);
    }
    return;
}
int lca(int x,int y){
    int ans=1e9;
    if(deep[x]<deep[y])swap(x,y);
    for(int i=20;i>=0;i--){
        if(deep[f[x][i]]>=deep[y]){
            ans=min(ans,dis[x][i]);//一定先更新ans,再让x,y往上跳,下面同理.
            x=f[x][i];
        }
    }
    if(x==y)return ans;
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            ans=min(ans,min(dis[x][i],dis[y][i]));
            x=f[x][i];y=f[y][i];
        }
    }
    ans=min(ans,min(dis[x][0],dis[y][0]));
    return ans;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        e[i].from=read();
        e[i].to=read();
        e[i].w=read();
    }
    kruskal();//构建最大生成树
    for(int i=1;i<=n;i++){
        if(visit[i])continue;
        deep[i]=1;
        dfs(i);
        f[i][0]=i;dis[i][0]=1e9;
    }//预处理,有些点不一定连通(即有可能是森林)
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
        }//LCA的预处理
    Q=read();
    while(Q--){
        int x=read(),y=read();
        if(find(x)!=find(y))puts("-1");
        else printf("%d\n",lca(x,y));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10542860.html

时间: 2024-10-18 00:44:17

货车运输(最大生成树,LCA)的相关文章

luogu1967[NOIP2013D1T3] 货车运输 (最大生成树+LCA)

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

NOIP2013 货车运输(最大生成树+LCA)

模拟考试的时候暴搜,结果写丑了,分都不分 下来啃了一下题解,发现要用到一个叫做倍增的东西,还没有学过.但是老师说的,没有那个东西,写暴力也有30~40分... 我觉得最大生成树还是很好理解的,因为我们要求的是图中任意两个点之间的路径上,使得边权的最小值尽量大.因此首先求最大生成树. 当我们得到最大生成树后,要求两个点之间边权最小值,我们可以首先找到他们的公共祖先.这里有一篇写得很详细的代码,并且注明了各种写法的得分http://blog.csdn.net/gengmingrui/article/

$Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$

$Luogu$ $Sol$ 首先当然是构建一棵最大生成树,然后对于一辆货车的起点和终点倍增跑$lca$更新答案就好.记得预处理倍增的时候不仅要处理走了$2^i$步后是那个点,还有这中间经过的路径权值的最小值以便之后统计答案. 再一看发现这题并没说给的图是联通的,也就是说跑了最大生成树之后可能有若干棵树.所以构树的时候要注意不能随便选一个点构完就不管了,要对每一个联通块都构一次.其他的地方似乎没有因为它有多棵树而有什么不同,只是询问的时候看下是不是一个联通块里的就好. $Code$ #includ

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

洛谷 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

【luogu1967】【noip2013】 货车运输 [生成树kruskal LCA ]

P1967 货车运输最大生成树+倍增算路径最小值 最大生成树就是kruskal时将边改为降序 然后就和普通kruskal一样 然后就是用的LCA倍增模板中说的其它骚操作一样 可以在预处理的时候还可以顺便记录下这段路径的权值最大值 最小值或者权值和之类的信息,这样就可以在O(logn)的时间内求出树上两点间路径权值的最大值.最小值还有权值和 #include<iostream> #include<cstdio> #include<queue> #include<cs

倍增LCA NOIP2013 货车运输

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

poj1330|bzoj3732|noip2013 货车运输 kruskal+倍增lca

学了一早上倍增,感觉lca还是tarjan好写. poj1330 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <algorithm> 5 #define DEG 20//2^20 6 #define maxn 10010 7 using namespace std; 8 struct node 9 { 10 int v, next; 11 }a[maxn*2

C++之路进阶——LCA(货车运输)

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和