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

    次小生成树Treehttps://www.luogu.org/problemnew/show/P4180

    题目描述

    小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)

    [∑e∈EMvalue(e)<∑e∈ESvalue(e) ]

    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    输入格式:

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

    输出格式:

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    先Kruscal最小生成树,然后枚举非树边,权值为w,将边的两端点的路径(LCA)上的最长边用w替换,但由于我们求的是严格次小生成树,所以当最长边边权==w时,需要用严格次大边替代,因此用倍增维护LCA上的严格次大值和最大值.
    具体见代码注释:

    #define LL long long
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define RG register
    using namespace std;
    const int N=1e5+5,M=3e5+5;
    inline LL read()
    {
        RG int x=0,w=1;RG char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    inline LL min(LL a,LL b){return a<b?a:b;}
    inline LL max(LL a,LL b){return a>b?a:b;}
    LL n,m,cnt,num,Cost,Ans=100000000000000;
    LL last[N],par[N],dep[N],f[N][25],f1[N][25],f2[N][25];
    //f[i][j]表示i节点2^j祖先的序号,f1[i][j]表示从i到f[i][j]路径上的最大边权,f1[i][j]表示严格次大边权.
    bool used[M];
    struct edge{//邻接表
        LL to,next,w;
    }e[2*M];
    struct edgm{//存边
        LL u,v,w;
    }e1[M];
    void insert(LL u,LL v,LL w)
    {
        e[++cnt]=(edge){v,last[u],w};last[u]=cnt;
        e[++cnt]=(edge){u,last[v],w};last[v]=cnt;
    }
    bool cmp(edgm a,edgm b){return a.w<b.w;}
    LL find(LL x){return x==par[x]?x:par[x]=find(par[x]);}
    void Kruskal()
    {
        for(LL i=1;i<=m;i++)
        {
            if(num==n-1)break;
            LL a=e1[i].u,b=e1[i].v;
            int fa=find(a),fb=find(b);
            if(fa==fb)continue;
            par[fa]=fb;
            Cost+=e1[i].w;//最小生成树
            num++;
            used[i]=1;//标记树中的边
            insert(a,b,e1[i].w);
        }
    }
    void dfs(LL now)//处理深度和f[i][0]以及f1[i][0]
    {
        for(LL i=last[now];i;i=e[i].next)
        {
            LL v=e[i].to;
            if(dep[v])continue;
            dep[v]=dep[now]+1;
            f[v][0]=now;
            f1[v][0]=e[i].w;
            f2[v][0]=-100000000000000;//f2[i][0]置为-inf
            dfs(v);
        }
    }
    void init()
    {
        dep[1]=1;
        dfs(1);
        for(LL j=1;j<=20;j++)//递推过程
            for(LL i=1;i<=n;i++)
            {
                f[i][j]=f[f[i][j-1]][j-1];
                f1[i][j]=max(f1[i][j-1],f1[f[i][j-1]][j-1]);
                if(f1[i][j-1]==f1[f[i][j-1]][j-1])f2[i][j]=max(f2[i][j-1],f2[f[i][j-1]][j-1]);
                else f2[i][j]=max(min(f1[i][j-1],f1[f[i][j-1]][j-1]),max(f2[i][j-1],f2[f[i][j-1]][j-1]));
            }
    }
    LL LCA(LL a,LL b,LL w)
    {
        LL dwq[200];//将可能的取值放进数组中,排序方便处理
        LL ct=0;
        memset(dwq,0,sizeof(dwq));
        if(dep[b]>dep[a])swap(a,b);
        for(LL i=20;i>=0;i--)//倍增
        {
            if(f[a][i]&&dep[f[a][i]]>=dep[b])
            {
                dwq[++ct]=f1[a][i];
                dwq[++ct]=f2[a][i];
                a=f[a][i];
            }
        }
        if(a!=b)
        {
            for(LL i=20;i>=0;i--)
                if(f[a][i]&&f[b][i]&&f[a][i]!=f[b][i])
                {
                    dwq[++ct]=f1[a][i];
                    dwq[++ct]=f2[a][i];
                    dwq[++ct]=f1[b][i];
                    dwq[++ct]=f2[b][i];
                    a=f[a][i];
                    b=f[b][i];
                }
            dwq[++ct]=f1[a][0];
            dwq[++ct]=f1[b][0];
            dwq[++ct]=f2[a][0];
            dwq[++ct]=f2[b][0];
        }
        sort(dwq+1,dwq+ct+1);
        for(LL i=ct;i>=1;i--)if(dwq[i]<w)return dwq[i];
    }
    int main()
    {
        n=read();m=read();
        for(LL i=1;i<=n;i++)par[i]=i;
        for(LL i=1;i<=m;i++)e1[i]=(edgm){read(),read(),read()};
        sort(e1+1,e1+m+1,cmp);
        Kruskal();
        init();
        for(LL i=1;i<=m;i++)
        {
            if(used[i])continue;
            LL a=e1[i].u,b=e1[i].v,w=e1[i].w;
            Ans=min(Ans,Cost-LCA(a,b,w)+w);//取最小值
        }
        printf("%lld
    ",Ans);
        return 0;
    }
    
  • 相关阅读:
    Session的使用与Session的生命周期
    Long-Polling, Websockets, SSE(Server-Sent Event), WebRTC 之间的区别与使用
    十九、详述 IntelliJ IDEA 之 添加 jar 包
    十八、IntelliJ IDEA 常用快捷键 之 Windows 版
    十七、IntelliJ IDEA 中的 Maven 项目初体验及搭建 Spring MVC 框架
    十六、详述 IntelliJ IDEA 创建 Maven 项目及设置 java 源目录的方法
    十五、详述 IntelliJ IDEA 插件的安装及使用方法
    十四、详述 IntelliJ IDEA 提交代码前的 Code Analysis 机制
    十三、IntelliJ IDEA 中的版本控制介绍(下)
    十二、IntelliJ IDEA 中的版本控制介绍(中)
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/8425656.html
Copyright © 2011-2022 走看看