P4180 [BJWC2010] 严格次小生成树

P4180 [BJWC2010] 严格次小生成树

题目描述

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

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

数据范围:

数据中无向图不保证无自环

对于 \(100\%\) 的数据, \(N\le 10^5\)\(M\le 3\times10^5\),边权 \(\in [0,10^9]\),数据保证必定存在严格次小生成树。

Solution:

又是美味的 LCT 维护最小生成树捏。我们稍微思考一下就能想到我们明显只能换掉一条边,所以我们先使用 LCT 跑一便最小生成树并记录该联通块内的最大值与严格次大值 \(mx_0,mx_1\),然后枚举每一条 非树边 ,判断其与 \(mx_0,mx_1\) 的大小关系然后更新答案,但是不用换边 因为 我们明显只能换掉一条边

然后说一下我们为什么要记录次大值:当然是因为非树边的权值有可能等于树边了。

然后这题就被我们解决了(离放假又进一步) ヾ(´∀ ˋ)ノ

Code:

#include<bits/stdc++.h>
#define ll long long
const int N=4e5+5;
const ll inf=1e17;
using namespace std;
struct LCT{
    int w[N],st[N];
    struct Tree{
        int tag,ff,ch[2],mx[2];
    }t[N];
    #define ls t[x].ch[0]
    #define rs t[x].ch[1]
    #define fa t[x].ff
    inline bool isroot(int x)
    {
        return (t[fa].ch[0]==x||t[fa].ch[1]==x);
    }
    inline void upd(int x,int y)
    {
        if(t[x].mx[0]<t[y].mx[0])
        {
            t[x].mx[1]=t[x].mx[0];
            t[x].mx[0]=t[y].mx[0];
            if(t[x].mx[1]<t[y].mx[1])
            {
                t[x].mx[1]=t[y].mx[1];
            }
        }
        else
        {
            if(t[x].mx[1]<t[y].mx[0])
            {
                t[x].mx[1]=t[y].mx[0];
            }
        }
    }
    inline void pushup(int x)
    {
        t[x].mx[0]=w[x];
        if(ls)upd(x,ls);
        if(rs)upd(x,rs);
        return;
    }
    inline void rev(int x)
    {
        swap(t[x].ch[0],t[x].ch[1]);
        t[x].tag^=1;
        return ;
    }
    inline void pushdown(int x)
    {
        if(t[x].tag)
        {
            if(ls)rev(ls);
            if(rs)rev(rs);
            t[x].tag=0;
        }
        return ;
    }
    inline void rotate(int x)
    {
        int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0;
        if(isroot(y))t[z].ch[t[z].ch[1]==y]=x;
        t[x].ff=z;

        t[y].ch[k]=t[x].ch[!k];
        if(t[x].ch[!k])t[t[x].ch[!k]].ff=y;

        t[x].ch[!k]=y;
        t[y].ff=x;
        pushup(y);
    }
    inline void splay(int x)
    {
        int y=x,z=0;
        st[++st[0]]=y;
        while(isroot(y))st[++st[0]]=y=t[y].ff;
        while(st[0])pushdown(st[st[0]--]);
        while(isroot(x))
        {
            y=fa,z=t[fa].ff;
            if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);}
            rotate(x);
        }
        pushup(x);
    }
    void access(int x)
    {
        int y=0;
        while(x)
        {
            splay(x);rs=y;pushup(x);
            y=x;x=fa;
        }
    }
    void make_root(int x)
    {
        access(x);splay(x);
        rev(x);
    }
    int find(int x)
    {
        access(x);splay(x);
        while(ls)pushdown(x),x=ls;
        splay(x);
        return x;
    }
    void splite(int x,int y)
    {
        make_root(x);
        access(y);splay(y);
    }
    void link(int x,int y)
    {
        make_root(x);
        if(find(y)!=x)t[x].ff=y;
        return ;
    }
    void cut(int x) // 这里是减去一个点 x
    {
        splay(x);
        t[ls].ff=t[rs].ff=0;
        return ;
    }
    bool check(int x,int y)
    {
        make_root(x);
        return find(y)==x;
    }
}T;
struct Edge{
    int u,v,w;
    bool operator <(const Edge &e)const{
        return w<e.w;
    }
};
vector<Edge> E;
int n,m,tot,cnt=0;
ll ans,tmp=0;
int tag[N];
void work()
{
    cin>>n>>m;ans=inf;
    tot=n;
    for(int i=1,u,v,w;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        E.push_back((Edge){u,v,w});
    }
    sort(E.begin(),E.end());
    for(auto [u,v,w] : E)
    {
        T.w[++tot]=w;
        if(!T.check(u,v))
        {
            T.link(u,tot);T.link(tot,v);cnt++;tmp+=w;
            tag[tot]=1;
        }
    }
    tot=n;
    for(auto [u,v,w] : E)
    {
        if(tag[++tot]||u==v)continue;
        T.splite(u,v);
        int mx[2]={T.t[v].mx[0],T.t[v].mx[1]};
        if(w>mx[0]&&mx[0])
        {
           ans=min(ans,tmp-mx[0]+w);
        }
        else if(w>mx[1]&&mx[1])
        {
            ans=min(ans,tmp-mx[1]+w);
        }

    }
    printf("%lld\n",ans);
}
int main()
{
    //freopen("P4180_1.in","r",stdin);freopen("tree.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-01-24 16:31  liuboom  阅读(21)  评论(0)    收藏  举报