zoukankan      html  css  js  c++  java
  • 次小生成树

    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("
    ");
        for(int i=1;i<=m*2;i++)
            printf("%d %d %d
    ",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
    ",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;
    }
  • 相关阅读:
    linux 用tcpdump查看80端口访问有哪些IP
    yum-内网yum源服务器配置(CentOS6.5)
    linux 修改用户密码的几种方法
    ansible hosts文件编写,简单使用测试(普通用户、sudo用户、root用户登录权限测试)
    ansible 安装
    ansible教程
    iowait过高处理
    重装系统win10教程(激活系统、office下载、分区)
    Spingboot项目的创建与启动(基于IDEA)
    反射
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11655761.html
Copyright © 2011-2022 走看看