zoukankan      html  css  js  c++  java
  • 一本通1555【例 4】次小生成树

    1555:【例 4】次小生成树

    时间限制: 1000 ms         内存限制: 524288 KB

    题目描述

    原题来自:BeiJing 2010 组队赛

    给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。

    设最小生成树的边权之和为 sum,严格次小生成树就是指边权之和大于 sum 的生成树中最小的一个。

    输入格式

    第一行包含两个整数 N 和 M,表示无向图的点数与边数;

    接下来 MM 行,每行三个数 x,y,z,表示点 x 和点 y 之间有一条边,边的权值为 z

    输出格式

    包含一行,仅一个数,表示严格次小生成树的边权和。

    数据保证必定存在严格次小生成树。

    样例

    样例输入

    5 6 
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6

    样例输出

    11

    数据范围与提示

    对于全部数据,1N10^5,1M3×10^5,数据中无向图无自环,边权值非负且不超过 10^9

    sol:严格次小生成树模板,我使用倍增做的,树剖也可以(表示不清楚别人为什么这么快)

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100005,M=300005,inf=0x3f3f3f3f;
    int n,m;
    struct Edge
    {
        int U,V,Val;
    }E[M];
    inline bool cmp(Edge p,Edge q)
    {
        return p.Val<q.Val;
    }
    int Father[N];
    long long MST=0;
    bool Edge_Bo[M];
    inline int Get_Father(int x)
    {
        return (Father[x]==x)?(x):(Father[x]=Get_Father(Father[x]));
    }
    struct Tree
    {
        int tot,Next[M],to[M],head[N],val[M];
        inline void add(int x,int y,int z)
        {
            Next[++tot]=head[x];
            to[tot]=y;
            val[tot]=z;
            head[x]=tot;
            return;
        }
        int Depth[N],F[N][23];
        int Val_Zd[N][23],Val_Cd[N][23];
        inline void dfs(int x,int fa)
        {
            F[x][0]=fa; Depth[x]=Depth[fa]+1;
            int i;
            for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
            {
                Val_Zd[to[i]][0]=val[i];
                Val_Cd[to[i]][0]=-inf;
                dfs(to[i],x);
            }
            return;
        }
        inline void Pre()
        {
            int i,j;
            dfs(1,0);
            for(i=1;i<=19;i++)
            {
                for(j=1;j<=n;j++)
                {
                    F[j][i]=F[F[j][i-1]][i-1];
                    Val_Zd[j][i]=max(Val_Zd[j][i-1],Val_Zd[F[j][i-1]][i-1]);
                    Val_Cd[j][i]=max(Val_Cd[j][i-1],Val_Cd[F[j][i-1]][i-1]);
                    if(Val_Zd[j][i-1]<Val_Zd[F[j][i-1]][i-1]) Val_Cd[j][i]=max(Val_Cd[j][i],Val_Zd[j][i-1]);
                    else if(Val_Zd[F[j][i-1]][i-1]<Val_Zd[j][i-1]) Val_Cd[j][i]=max(Val_Cd[j][i],Val_Zd[F[j][i-1]][i-1]);
                }
            }
            return;
        }
        inline int Ask_Lca(int x,int y)
        {
            int i;
            if(Depth[x]<Depth[y]) swap(x,y);
            for(i=19;~i;i--) if(Depth[F[x][i]]>=Depth[y]) x=F[x][i];
            if(x==y) return x;
            for(i=19;~i;i--) if(F[x][i]!=F[y][i]) x=F[x][i],y=F[y][i];
            return F[x][0];
        }
        inline int Ask_Lower(int x,int y,int z)
        {
            int i,Now=x,ans=0;
            for(i=19;~i;i--) if(Depth[F[Now][i]]>=Depth[y])
            {
    //            printf("Now=%d Val_Zd[Now][i]=%d BB=%d
    ",Now,Val_Zd[Now][i],z);
    //            printf("Now=%d Val_Cd[Now][i]=%d BB=%d
    ",Now,Val_Cd[Now][i],z);
                if(Val_Zd[Now][i]<z) ans=max(ans,Val_Zd[Now][i]);
                else ans=max(ans,Val_Cd[Now][i]);
                Now=F[Now][i];
            }
            return ans;
        }
    }T;
    int main()
    {
        int i;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++) Father[i]=i;
        for(i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            E[i]=(Edge){x,y,z};
        }
        sort(E+1,E+m+1,cmp);
        for(i=1;i<=m;i++)
        {
            int xx=Get_Father(E[i].U),yy=Get_Father(E[i].V);
            if(xx==yy) continue;
            Father[xx]=yy; MST+=E[i].Val; Edge_Bo[i]=1;
            T.add(E[i].U,E[i].V,E[i].Val); T.add(E[i].V,E[i].U,E[i].Val);
        }
    //    printf("MST=%d
    ",MST);
        T.Pre();
        long long ans=0x7ffffffffff;
        for(i=1;i<=m;i++) if(!Edge_Bo[i])
        {
            int x=E[i].U,y=E[i].V,z=E[i].Val;
            int ll=T.Ask_Lca(x,y);
    //        printf("x=%d y=%d ll=%d
    ",x,y,ll);
            int p1=T.Ask_Lower(x,ll,z),p2=T.Ask_Lower(y,ll,z);
    //        printf("p1=%d p2=%d
    ",p1,p2);
            ans=min(ans,MST-max(p1,p2)+z);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    /*
    input
    5 6 
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6
    output
    11
    */
    View Code
  • 相关阅读:
    12.9Java日报
    2020-12-10日报博客-周四
    2020-12-9日报博客-周三
    2020-12-8日报博客-周二
    2020-12-7日报博客-周一
    2020-12-6日报博客-一周总结
    2020-12-4日报博客-周五
    .NET ------ 界面显示优化(新增,查询窗口)
    构建之法阅读笔记——程序员篇
    Eclipse的Junit单元测试
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10352826.html
Copyright © 2011-2022 走看看