专栏首页数据结构与算法洛谷P4180 [Beijing2010组队]次小生成树Tree

洛谷P4180 [Beijing2010组队]次小生成树Tree

题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1

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

输出样例#1: 

11

说明

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

裸的次小生成树

具体怎么实现一会儿整理一下挂个链接吧

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#define int long long 
using namespace std;
const int MAXN=400001;
const int INF=1e15+10;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct Edge
{
    int u,v,w;
}E[MAXN];
int Enum=1;
void Add(int x,int y,int z)
{
    E[Enum].u=x;
    E[Enum].v=y;
    E[Enum].w=z;Enum++;
}
struct node
{
    int u,v,w,nxt;
}edge[MAXN];
int head[MAXN];
int num=1;
int N,M;
int fa[MAXN],vis[MAXN],sum;
int deep[MAXN],f[MAXN][21],maxx[MAXN][21],minx[MAXN][21];
void AddEdge(int x,int y,int z)
{
    edge[num].u=x;
    edge[num].v=y;
    edge[num].w=z;
    edge[num].nxt=head[x];
    head[x]=num++;
}
int find(int x)
{
    if(fa[x]==x) return fa[x];
    else return fa[x]=find(fa[x]);
}
int unionn(int x,int y)
{
    int fx=find(x),fy=find(y);
    fa[fx]=fy;
}
int comp(const Edge &a,const Edge &b)
{
    return a.w<b.w;
}
void Kruskal()
{
    sort(E+1,E+Enum,comp);
    int tot=0;
    for(int i=1;i<=Enum-1;i++)
    {
        int x=E[i].u,y=E[i].v;
        if(find(x)!=find(y)) 
        {
            unionn(x,y),tot++,sum+=E[i].w,vis[i]=1;
            AddEdge(x,y,E[i].w);AddEdge(y,x,E[i].w);
        }
        if(tot==N-1) break;
    }
}
void dfs(int now,int fa)
{
    for(int i=head[now];i!=-1;i=edge[i].nxt)
    {
        if(edge[i].v==fa) continue;
        deep[edge[i].v]=deep[edge[i].u]+1;
        f[edge[i].v][0]=now;
        maxx[edge[i].v][0]=edge[i].w;
        dfs(edge[i].v,now);
    }
}
void pre()
{
    for(int i=1;i<=18;i++)
    {
        for(int j=1;j<=N;j++)
        {
            f[j][i]=f[ f[j][i-1] ][i-1];
            maxx[j][i]=max(maxx[j][i-1],maxx[ f[j][i-1] ][i-1]);
            minx[j][i]=max(minx[j][i-1],minx[ f[j][i-1] ][i-1]);
            if(maxx[j][i-1]>maxx[ f[j][i-1] ][i-1]) minx[j][i]=max(minx[j][i],maxx[ f[j][i-1] ][i-1]);
            else minx[j][i]=max(minx[j][i],maxx[j][i-1]);
        }
    }
}
int LCA(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    for(int i=18;i>=0;i--)
        if(deep[ f[x][i] ] >= deep[y] ) 
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;i>=0;i--)
        if(f[x][i] != f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int findmax(int x,int lca,int val)
{
    int ans=0;
    for(int i=18;i>=0;i--)
    {
        if(deep[ f[x][i] ] >= deep[lca]) 
        {
            if(maxx[x][i]==val) ans=max(ans,minx[x][i]);
            else ans=max(ans,maxx[x][i]);
            x=f[x][i];
        }
    }
    return ans;
}
void work()
{
    int ans=INF;
    for(int i=1;i<=Enum-1;i++)
    {
        if(vis[i]) continue;
        int x=E[i].u,y=E[i].v,z=E[i].w;
        int lca=LCA(x,y);
        int lmx=findmax(x,lca,z);
        int rmx=findmax(y,lca,z);
        if(max(lmx,rmx)!=z)
        ans=min(ans,sum+z-max(lmx,rmx));
    }
    printf("%lld",ans);
}
main()
{  
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    N=read(),M=read();
    memset(head,-1,sizeof(head));
    for(int i=1;i<=N;i++) fa[i]=i;
    for(int i=1;i<=M;i++)
    {
        int x=read(),y=read(),z=read();
        Add(x,y,z);
    }
    Kruskal();
    deep[1]=1;
    dfs(1,0);
    pre();
    work();
    return 0;  
}  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • P3368 【模板】树状数组 2 单点查询与区间修改

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数...

    attack
  • BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)

    不难发现题目给出的是一个树,其中\(\frac{i}{K}\)是\(i\)的父亲节点

    attack
  • P1629 邮递员送信(未完成)

    题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,...

    attack
  • 2016天梯模拟赛 进阶题解

    L2-005 集合相似度 题目链接: https://www.patest.cn/contests/gplt/L2-005 题目的意思是要求两个集合的交集中...

    ShenduCC
  • 一遍记住Java常用的八种排序算法与代码实现

    (如果每次比较都交换,那么就是交换排序;如果每次比较完一个循环再交换,就是简单选择排序。)

    田维常
  • HDU 1573 X问题

    Problem Description 求在小于等于N的正整数中有多少个X满足: Input 输入数据的第一行为一个正整数T,表示有T组测试数据。每组测...

    attack
  • Day2上午解题报告

    预计分数:100+0+60=160 实际分数:100+0+60=160 mmpT1数据错了。。。 T1遭遇 题目描述 你是能看到第一题的 friends呢。 —...

    attack
  • LeetCode 第 210 场周赛 解题报告

    那么在遍历过程中,栈中元素数量的最大值即为答案。栈中的(可以理解为还没遍历到匹配的),即那些嵌套的(。

    ACM算法日常
  • 次小生成树

    次小生成树 次小生成树 我们已经熟知了求最小生成树的方法,用kruskal,prim算法都可以搞 那么我们如何求次小生成树呢? 这里次小生成树的定义是 边...

    attack
  • 图论--拓扑排序--判断一个图能否被拓扑排序

    拓扑排序的实现条件,以及结合应用场景,我们都能得到拓扑排序适用于DAG图(Directed Acyclic Graph简称DAG)有向无环图, 根据关系我们能得...

    风骨散人Chiam

扫码关注云+社区

领取腾讯云代金券