zoukankan      html  css  js  c++  java
  • p4180 次小生成树

    传送门

    分析

    次小生成树的求法有两种,最大众的一种是通过倍增LCA找环中最大边求解,而这里我介绍一种神奇的O(nlogn) 做法:

        我们先建立最小生成树,因为我们用kruskal求解是边的大小已经按升序排列,所以相同情况下,先枚举的边一定更优,所以我们每一次暴力的找非树边所连两点的LCA,并在寻找过程中对经过的边染色同时将其加入并查集以防止其二次查询(为何只需查找一次之前已经说过),然后在最后,我们只需找出所染颜色所代表的边的权值减去被染色的边的权值的最小值即可。因为被染色的树边共有n-1条,所以此过程的复杂度是O(m),因此总复杂度即为快排复杂度O(mlogm)。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<map>
    #include<vector>
    #include<set>
    #include<ctime>
    #include<cctype>
    using namespace std;
    long long fa[110000],tot,used[310000],f[110000],col[310000],dep[110000];
    long long ari[110000],is[110000];
    long long sum=1;
    struct node{
        long long x,y,z;
    }d[310000];
    struct edge{
        long long from,to,nxt,w,id;
    }e[610000];
    long long head[610000];
    void add(long long x,long long y,long long z,long long id){
        e[sum].to=y;
        e[sum].nxt=head[x];
        e[sum].w=z;
        e[sum].id=id;
        head[x]=sum++;
        e[sum].to=x;
        e[sum].nxt=head[y];
        e[sum].w=z;
        e[sum].id=id;
        head[y]=sum++;
        return;
    }
    bool cmp(const node &p,const node &q){
        return p.z<q.z;
    }
    long long sf(long long a){
        return fa[a]==a?a:fa[a]=sf(fa[a]);
    }
    void dfs(long long a,long long fat){
        long long i,j,k;
        for(i=head[a];i;i=e[i].nxt)
           if(e[i].to!=fat){
            dep[e[i].to]=dep[a]+1;
            f[e[i].to]=a;
            ari[e[i].to]=e[i].id;
            dfs(e[i].to,a);
        }
        return;
    }
    long long ff(long long a){
        return is[a]==a?a:is[a]=ff(is[a]);
    }
    void mer(long long u,long long v,long long c){
        u=ff(u),v=ff(v);
        while(u!=v){
            if(dep[u]<dep[v])swap(u,v);
            col[ari[u]]=c;
            is[u]=ff(f[u]);
            u=ff(u);
        }
        return;
    }
    int main(){
        //freopen("1.in","r",stdin);
        long long n,m,i,j,k;
        scanf("%lld%lld",&n,&m);
        for(i=1;i<=m;i++){
           scanf("%lld%lld%lld",&d[i].x,&d[i].y,&d[i].z);
        }
        //建最小生成树
        sort(d+1,d+m+1,cmp);
        long long cnt=0,p,q;
        for(i=1;i<=n;i++){
           fa[i]=i;
           f[i]=i;
           is[i]=i;
        }
        for(i=1;i<=m;i++){
            p=sf(d[i].x),q=sf(d[i].y);
            if(p!=q){
                cnt++;
                if(rand()%2)fa[p]=q;
                  else fa[q]=p;        
                tot+=d[i].z;
                used[i]=1;
                add(d[i].x,d[i].y,d[i].z,i);
            }
            if(cnt==n-1)break;
        }
        //初始化,f表示父子关系,is用于新并查集
        dfs(1,0);
        for(i=1;i<=m;i++)
           if(!used[i]){
                mer(d[i].x,d[i].y,i);
           }
        //求答案
        long long ans=1000000007;
        for(i=1;i<=m;i++)
           if(used[i]){
                if(col[i]&&d[col[i]].z!=d[i].z)
                  ans=min(ans,d[col[i]].z-d[i].z);
           }
        printf("%lld ",ans+tot);
        return 0;
    }

  • 相关阅读:
    LeetCode 230. Kth Smallest Element in a BST
    LeetCode 114. Flatten Binary Tree to Linked List
    LeetCode 222. Count Complete Tree Nodes
    LeetCode 129. Sum Root to Leaf Numbers
    LeetCode 113. Path Sum II
    LeetCode 257. Binary Tree Paths
    Java Convert String & Int
    Java Annotations
    LeetCode 236. Lowest Common Ancestor of a Binary Tree
    LeetCode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9016111.html
Copyright © 2011-2022 走看看