一本通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

数据范围与提示

对于全部数据,1≤N≤10^5,1≤M≤3×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\n",Now,Val_Zd[Now][i],z);
//            printf("Now=%d Val_Cd[Now][i]=%d BB=%d\n",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\n",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\n",x,y,ll);
        int p1=T.Ask_Lower(x,ll,z),p2=T.Ask_Lower(y,ll,z);
//        printf("p1=%d p2=%d\n",p1,p2);
        ans=min(ans,MST-max(p1,p2)+z);
    }
    printf("%lld\n",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
*/

原文地址:https://www.cnblogs.com/gaojunonly1/p/10352826.html

时间: 2024-09-30 09:18:48

一本通1555【例 4】次小生成树的相关文章

次小生成树(SST)

次小生成树(SST) 题目背景 Awson是某国际学校信竞组的一只菜鸡.Awson最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当Awson洋洋得意之时,信竞组其他大佬又来泼Awson冷水了. 题目描述 他们说,让Awson求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:              (value(e) 表示边 e的权值)这下Awson蒙了,他

COGS 1578. 次小生成树初级练习题

☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式] 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数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

次小生成树

次小生成树:所谓的次小生成树,是指在边集与某一最小生成树的边集不完全相同的其它生成树中值最小的那个.因此在数值上,最小生成树可能会等于次小生成树,这种情况也可以看做最小生成数. 思路:最直观的解法是,首先求出最小生成树,并且记录最小生成树中的边,然后再枚举删除最小生成树的边并同时求最小生成树. 以POJ1679为例,Kruskal求次小生成树代码如下: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm>

NYOJ修路方案【次小生成树】

修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输

修路方案(次小生成树)

修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输

COGS——T 1578. 次小生成树初级练习题

http://www.cogs.pro/cogs/problem/problem.php?pid=1578 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式] 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z. [输出格式] 包含一行,仅一个数,表示严格次小生成树的边权和.(数据保证必定存在

cogs——1578. 次小生成树初级练习题

1578. 次小生成树初级练习题 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式] 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z. [输出格式] 包含一行,仅一个数,表示严格次小生成树的边权和.(数据保证必定存在严格次小生成树) [样例输入] 5 6 1 2 1 1 3 2 2 4 3

cogs P1578【模板】 次小生成树初级练习题

1578. 次小生成树初级练习题 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式] 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z. [输出格式] 包含一行,仅一个数,表示严格次小生成树的边权和.(数据保证必定存在严格次小生成树) [样例输入] 5 6 1 2 1 1 3 2 2 4 3

[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) 这下小