洛谷 P1967 货车运输(Kruskal最大生成树&&倍增lca)

传送门
这个题我本来看出来了,也想到做法了,然后打了130行的代码,开始调,好不容易调过样例,然后就交;
第一次CE,改了继续交;
第二次10分,我当时就崩溃,我写了这么长时间,还不如30分无脑暴力??我就看题解,果然算法就是这样,然后,比对了好几个,也没看见什么错,倒是跟着他们优化了优化常数,然后又交;
第三次还是10分,我已经麻木了,放弃了看题解,开始对着自己的代码肉眼debug,结果又优化了好多小常数,还是看不出来错误;
第四次当然没变化,我就开始对着代码发呆,看呀看,看呀看,不知道过了多久,我看了不知道多少遍代码之后,我发现了一丝不对劲,我的lca预处理怎么怪怪的,我就翻出来以前的lca,对比,发现我的代码是倒着算的!立刻改了,然后调了一会儿,就过样例了,然后交;
第五次AC!!
全程用时:1.5h+
真的今天运气太烂,洛谷的大凶还是很准的。。。


题解

首先看题,大概是这样:
给定一个无向图,多次询问两点之间路径上最大边最小化。
首先,它只问最大,所以可以直接转化成Kruskal最大生成树,然后一边倍增lca一边预处理一下,就可以像lca那样log查询了。
这题就是不好调试。。。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
struct edge{
    int x,y,w;
    inline bool operator < (const edge& b) const {
        return w>b.w;
    }
}e[100001];
int head[100001];
int to[100001];
int nxt[100001];
int w[100001];
int n,m;
int tot;
int fa[10001];
int st[10001][17];
int mn[10001][17];
int use[100001];
int dep[100001];
int vis[100001];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void addedge(int x,int y,int l){
    tot++;
    e[tot].x=x;
    e[tot].y=y;
    e[tot].w=l;
}
inline void addedge2(int x,int y,int l){
    tot++;
    to[tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    w[tot]=l;
}
void dfs(int x,int father,int l){
    vis[x]=1;
    dep[x]=dep[father]+1;
    mn[x][0]=l;
    st[x][0]=father;
    for(int i=head[x];i;i=nxt[i]){
        if(vis[to[i]]){
            continue;
        }
        dfs(to[i],x,w[i]);
    }
}
void getst(){
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            dfs(i,0,0);
        }
    }
    for(int k=1;k<=16;k++){
        for(int i=1;i<=n;i++){
            st[i][k]=st[st[i][k-1]][k-1];
            mn[i][k]=min(mn[i][k-1],mn[st[i][k-1]][k-1]);
        }
    }
}
int getlca(int x,int y){
    int ans=0x3f3f3f3f;
    if(dep[x]>dep[y]){
        swap(x,y);
    }
    for(int k=16;k>=0;k--){
        if(st[y][k])
        if(dep[st[y][k]]>=dep[x]){
            ans=min(ans,mn[y][k]);
            y=st[y][k];
            if(dep[x]==dep[y])break;
        }
    }
    if(x==y){
        return ans;
    }
    for(int k=16;k>=0;k--){
        if(st[x][k]!=st[y][k]){
            ans=min(ans,mn[x][k]);
            ans=min(ans,mn[y][k]);
            x=st[x][k];
            y=st[y][k];
        }
    }
    return min(ans,min(mn[x][0],mn[y][0]));
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int x,y,l;
        scanf("%d %d %d",&x,&y,&l);
        addedge(x,y,l);
    }
    sort(e+1,e+m+1);
    tot=0;
    for(int i=1,j=n;i<=m&&j!=1;i++){
        int u=find(e[i].x);
        int v=find(e[i].y);
        if(u!=v){
            fa[u]=v;
            j--;
            use[i]=1;
            addedge2(e[i].x,e[i].y,e[i].w);
            addedge2(e[i].y,e[i].x,e[i].w);
        }
    }
    getst();
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        if(find(x)!=find(y)){
            printf("-1
");
            continue;
        }
        int num=getlca(x,y);
        printf("%d
",num);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/stone41123/p/7581257.html