• 洛谷 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;
    }
  • 相关阅读:
    在peoplecode中直接调用SQR
    想起了李雷和韩梅梅
    结婚两周年纪念
    Unix Command Summary
    在PeopleSoft中如何隐藏菜单,导航栏,以及其他定制化链接
    那些朋友们
    整天工作的人为何当不了富翁
    ActiveX简单介绍
    SQL UNION
    Java程序设计问答大全(一)
  • 原文地址:https://www.cnblogs.com/stone41123/p/7581257.html
Copyright © 2020-2023  润新知