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

P1967 货车运输
最大生成树+倍增算路径最小值

最大生成树就是kruskal时将边改为降序 然后就和普通kruskal一样

然后就是用的LCA倍增模板中说的其它骚操作一样

可以在预处理的时候还可以顺便记录下这段路径的权值最大值 最小值或者权值和之类的信息,这样就可以在O(logn)的时间内求出树上两点间路径权值的最大值、最小值还有权值和

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define ll long long
#define rg register
const int N=100000+5,M=500000+5,inf=0x3f3f3f3f,P=19650827;
int n,m,q;
int dep[N],p[N][25],w[N][25];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch==‘-‘,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[N],tot=0,ans;
struct edge{int v,nxt,w;}e[M];
void add(int u,int v,int w){
    e[++tot]=(edge){v,head[u],w};head[u]=tot;
}

int f[N];
struct node{
    int u,v,w;
}nd[M];
bool cmp(node a,node b){return a.w>b.w;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void kruskal(){
    int cnt=0;
    for(rg int i=1;i<=n;++i) f[i]=i;
    for(rg int i=1,u,v,w;i<=m;++i){
        u=nd[i].u,v=nd[i].v,w=nd[i].w;
        if(find(u)!=find(v)){
            f[f[u]]=f[v];
            ++cnt;
            add(u,v,w),add(v,u,w);
            if(cnt==n-1) break;
        }
    }
}

void dfs(int u){
    for(int i=head[u],v;i;i=e[i].nxt){
        v=e[i].v;
        if(!dep[v]){//未走过
            dep[v]=dep[u]+1;
            p[v][0]=u;
            w[v][0]=e[i].w;
            dfs(v);
        }
    }
}
void build(){
    for(rg int i=1;i<=n;++i){
        if(!dep[i]){
            dep[i]=1;
            p[i][0]=0;
            dfs(i);
        }
    }
    dfs(1);//连起来
    for(int i=1; i<=20; i++)
        for(int j=1; j<=n; j++){
            p[j][i]=p[p[j][i-1]][i-1];
            w[j][i]=min(w[j][i-1], w[p[j][i-1]][i-1]);
        }
}

int LCA(int a,int b){
    ans=inf;
    if(dep[a]>dep[b]) swap(a,b);
    for(int i=20;i>=0;--i){
        if(dep[p[b][i]]<dep[a]) continue;
        ans=min(ans,w[b][i]);b=p[b][i];
    }
    if(a==b) return ans;
    for(int i=20;i>=0;--i){
        if(p[a][i]==p[b][i]) continue;
        ans=min(ans,min(w[a][i],w[b][i]));
        a=p[a][i],b=p[b][i];
    }
    ans=min(ans,min(w[a][0],w[b][0]));
    return ans;
}

int main(){
    //freopen("in.txt","r",stdin);
    memset(dep,0,sizeof(dep));
    memset(p,0,sizeof(p));
    rd(n),rd(m);
        int u,v,w;
    for(rg int i=1;i<=m;++i){
        rd(u),rd(v),rd(w);
        nd[i]=(node){u,v,w};
    }
    sort(nd+1,nd+1+m,cmp);
    kruskal();
    build();
    rd(q);
    for(rg int i=1;i<=q;++i){
        rd(u),rd(v);
        if(find(u)!=find(v)) printf("-1\n");
        else printf("%d\n",LCA(u,v));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lxyyyy/p/10960467.html

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

【luogu1967】【noip2013】 货车运输 [生成树kruskal LCA ]的相关文章

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

倍增LCA NOIP2013 货车运输

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

Codevs3278[NOIP2013]货车运输

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

noip2013货车运输

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

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/

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

【NOIP2013货车运输】

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

洛谷 1967 NOIP2013 货车运输

这个题目在看题解的情况下,写了6小时左右.感觉贼心累啊.读入错误,运行顺序错误,一大堆错误.现在很为自己写长代码担心... 毕竟花了这么长时间,在考场那种高压的情况下.还不知道发挥如何~ 题目说起来很Easy:1.读入2.求最大生成树3.求倍增求LCA 并记录 路径上的 最小值4.输出 放出我的丑不拉几的代码~ 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4   5 int Min[20