次小生成树

https://loj.ac/problem/10133

题目描述

  给出一张图,求它的严格次小生成树。

思路

  同秘密的牛奶运输,不再赘述。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+10,MAXM=3e5+10;
const ll INF=1000000000000000;
struct Edge
{
    ll x,y,w;
}e[MAXM];
ll fa[MAXN],tot,nxt[MAXM],to[MAXM],head[MAXN],w[MAXM];
ll f[MAXN][21],dep[MAXN];
ll g[MAXN][21][2];
bool used[MAXM];
void add_edge(ll x,ll y,ll v)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w[tot]=v;
}
bool cmp(Edge x,Edge y)
{
    return x.w<y.w;
}
ll find(ll x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
ll cal(ll x,ll k)
{
    ll y=f[x][k];
    if(g[x][k][0]==g[y][k][0])
        return max(g[x][k][1],g[y][k][1]);
    else if(g[x][k][0]<g[y][k][0])
        return max(g[x][k][0],g[y][k][1]);
    else return max(g[x][k][1],g[y][k][0]); 
}
void dfs(ll u,ll father)
{
    dep[u]=dep[father]+1;
    for(ll i=0;i<=19;i++)
    {
        f[u][i+1]=f[f[u][i]][i];
        g[u][i+1][0]=max(g[u][i][0],g[f[u][i]][i][0]);
        g[i][i+1][1]=cal(u,i);
    }
    for(ll i=head[u];i;i=nxt[i])
    {
        ll v=to[i];
        if(v==father)continue ;
        f[v][0]=u;
        g[v][0][0]=w[i];
        g[v][0][1]=-INF;
        dfs(v,u);
    }
}
ll LCA(ll x,ll y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(ll i=20;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y])x=f[x][i];
        if(x==y)return x;
    }
    for(ll i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}
ll qmax(ll x,ll y,ll w)
{
    ll ret=-INF;
    for(ll i=20;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
        {
            if(w!=g[x][i][0])ret=max(ret,g[x][i][0]);
            else ret=max(ret,g[x][i][1]);
            x=f[x][i];
        }
    return ret;
}
int main() 
{
    ll n,m;
    tot=0;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
        scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].w);
    sort(e+1,e+m+1,cmp);
    for(ll i=1;i<=n;i++)
        fa[i]=i;
/*        printf("\n");
    for(int i=1;i<=m*2;i++)
        printf("%d %d %d\n",e[i].x,e[i].y,e[i].w);*/
    ll cnt=0,sum=0;
    for(ll i=1;i<=m;i++)
    {
        ll fx=find(e[i].x),fy=find(e[i].y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            used[i]=1;
            add_edge(e[i].x,e[i].y,e[i].w);
            add_edge(e[i].y,e[i].x,e[i].w);
            cnt++;
            sum+=e[i].w;
            if(cnt==n-1)break ;
        }
    }
    dfs(1,0);
    ll ans=INF;
//    cout<<sum<<endl;
//    for(int i=1;i<=n;i++)
//        printf("%d\n",g[i][1]);
    for(ll i=1;i<=m;i++)
        if(!used[i])
        {
            ll lca=LCA(e[i].x,e[i].y);
            ll val=max(qmax(e[i].x,lca,e[i].w),qmax(e[i].y,lca,e[i].w));
//          cout<<e[i].x<<' '<<e[i].y<<endl;
//            cout<<val<<endl;
            ans=min(ans,sum-val+e[i].w);
        }
    printf("%lld",ans);
    return 0;
}

 

posted @ 2019-10-11 17:47  fbz  阅读(218)  评论(0编辑  收藏  举报