传送门

分析

次小生成树的求法有两种,最大众的一种是通过倍增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\n",ans+tot);
    return 0;
}

p4180 次小生成树的更多相关文章

  1. P4180 【模板】严格次小生成树[BJWC2010]

    P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...

  2. 【luogu P4180 严格次小生成树[BJWC2010]】 模板

    题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...

  3. 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)

    洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...

  4. Luogu P4180 【模板】严格次小生成树[BJWC2010]

    P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...

  5. 洛谷P4180【Beijing2010组队】次小生成树Tree

    题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...

  6. P4180 [BJWC2010]严格次小生成树

    P4180 [BJWC2010]严格次小生成树 P4180 题意 求出一个无向联通图的严格次小生成树.严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次 ...

  7. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  8. P4180 严格次小生成树[BJWC2010] Kruskal,倍增

    题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可 ...

  9. [Luogu P4180][BJWC 2010]严格次小生成树

    严格次小生成树,关键是“严格”,如果是不严格的其实只需要枚举每条不在最小生成树的边,如果得到边权和大于等于最小生成树的结束就行.原理就是因为Kruskal非常贪心,只要随便改一条边就能得到一个非严格的 ...

随机推荐

  1. Spark MLlib框架详解

    1. 概述 1.1 功能 MLlib是Spark的机器学习(machine learing)库,其目标是使得机器学习的使用更加方便和简单,其具有如下功能: ML算法:常用的学习算法,包括分类.回归.聚 ...

  2. 《UNIX网络编程》daytimetcpcli测试

    对于刚刚接触网络的人来说,<UNIX网络编程>中第一个例子(daytimetcpcli)可能就测试不通过.也许你试着继续向后读来,自己写一个服务程序来解决这个问题,但是daytime服务也 ...

  3. Logstash添加Protobuf解析插件

    logstash收集日志时,日志部分是由google的protobuf工具打印的,直接利用json解析会造成部分无法解析的问题 搜索后发现有个logstash的protobuf插件 在logstash ...

  4. EntityFramework 学习 一 Add Entity Graph using DbContext:

    //Create student in disconnected mode Student newStudent = new Student() { StudentName = "New S ...

  5. Python基础-操作mysql

    mysql 属于第三方模块,需要先安装 pip install pymysql,sql执行后,数据获取函数有三种cur.fetchone()#获取第一条数据,依次类推下去,第二次执行时候,就会取除去第 ...

  6. python遍历并获取对象属性--dir(),__dict__,getattr,setattr

    一.遍历对象的属性: 1.dir(obj) :返回对象的所以属性名称字符串列表(包括属性和方法). for attr in dir(obj): print(attr) 2.obj.__dict__:返 ...

  7. 7_DoubleBuffer 游戏编程中的双缓存模式

    ### double buffer 双缓存 简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替 #### the pattern 有两个缓存实例,一个是 current buffer, ...

  8. linux命令学习笔记(4):mkdir命令

    linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限, 并且指定的目录名不能是当前目录中已有的目录. .命令格式: mkdir [选项] 目录... .命令功 ...

  9. Java 时间和日期类型的 Hibernate 映射

    以下情况下必须显式指定 Hibernate 映射类型 一个 Java 类型可能对应多个 Hibernate 映射类型. 例如: 如果持久化类的属性为 java.util.Date 类型, 对应的 Hi ...

  10. python实现无序列表:链表

    介绍链表前我们先了解下什么是列表. 在对基本数据结构的讨论中,我们使用 Python 列表来实现所呈现的抽象数据类型.列表是一个强大但简单的收集机制,为程序员提供了各种各样的操作.然而,不是所有的编程 ...