zoukankan      html  css  js  c++  java
  • 严格次小生成树(模板)-洛谷4180

    传送门

    dr就这样咕咕咕了好几天

    (一时咕,一时爽,一直咕,那就gg了)

    我才不会承认

    我看题(概念)看了好久都没懂

    -----------------------------------------------------

    一、定义

      给出一个图

      可以形成若干个树

      将形成的树 按总比边权和的大小 从小到大排序

      第二小的就是次小生成树

    这时需要注意啦:

      若只是按排完序后的第二个树

      得到的是 不严格次小生成树

      因为 有可能排序后的第二个树 和 第一个树相等

      那么

      严格次小生成树 就是 和 第一棵树不等的 剩余树中的 最小的树

    (终于整明白定义了,就开始想想怎么做吧)

    二、算法

    先求出最小生成树

    (个人喜欢用kruskal)

    然后枚举出非树边

    把非树边加入到树中

    就会形成一个环

    就要删边

    (看看 哪次 加入非树边再删边 得到的生成树 是最小的<当然要大于最小生成树啦>)

    (每枚举到一条非树边 就是 一种情况的(一棵树)的判断)

    删边的原则?

    如果加进来的边与环上最大值不同,直接删掉最大值

    如果加进来的边与环上最大值相同,就删掉次大值

    如何高效的去找要删的边咧?(维护最大值和次大值)

    倍增LCA!!

    fa维护LCA

    maxi维护最大值

    mini维护次大值

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #define ll long long
    using namespace std;
    
    const ll N = 400010;
    const ll M = 900010;
    const ll INF = 2147483647000000;
    
    inline ll read()//快读 
    {
        ll sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    struct edge
    {
        ll u,v,d;
        ll next;
    }G[N << 1];
    ll tot,head[N];
    edge A[M<<1];
    bool vis[M<<1];
    ll fa[N];
    ll f[N][19]; 
    ll maxi[N][19];
    ll mini[N][19];
    ll deep[N];
    ll n,m;
    
    inline bool cmp(edge x,edge y)//快排 
    {
        return x.d < y.d;
    } 
    
    inline ll getfa(ll o)//找根节点 
    {
        if(o == fa[o])
            return o;
        else
            return fa[o] = getfa(fa[o]);
    }
    
    inline void add(ll u,ll v,ll d)//加边 
    {
        G[++tot].u = u;
        G[tot].v = v;
        G[tot].d = d;
        G[tot].next = head[u];
        head[u] = tot;
    }
    
    inline void dfs(ll o,ll x)//预处理 
    {
        f[o][0] = x;
        for(ll i = head[o];i;i = G[i].next)
        {
            ll v = G[i].v;
            if(v == x)
                continue;
            deep[v] = deep[o] + 1LL;
            maxi[v][0] = G[i].d;
            mini[v][0] = -INF;
            dfs(v,o);
        }
    }
    
    inline void cal()//倍增的思想求出最大值和次大值 
    {
        for(ll i = 1;i <= 18;i++)
            for(ll j = 1;j <= n;j++)
            {
                f[j][i] = f[f[j][i - 1]][i - 1];
                maxi[j][i] = max(maxi[j][i - 1],maxi[f[j][i - 1]][i - 1]);
                mini[j][i] = max(mini[j][i - 1],mini[f[j][i - 1]][i - 1]);
                if(maxi[j][i - 1] > maxi[f[j][i - 1]][i - 1])
                    mini[j][i] = max(mini[j][i],maxi[f[j][i - 1]][i - 1]);
                else
                if(maxi[j][i - 1] < maxi[f[j][i - 1]][i - 1])
                    mini[j][i] = max(mini[j][i],maxi[j][i - 1]);
            }
    }
    
    inline ll lca(ll x,ll y)//倍增lca 
    {
        if(deep[x] < deep[y])
            swap(x,y);
        for(ll i = 18;i >= 0;i--)
            if(deep[f[x][i]] >= deep[y])
                x = f[x][i];
        if(x == y)
            return x;
        for(ll i = 18;i >= 0;i--)
            if(f[x][i] ^ f[y][i])
            {
                x = f[x][i];
                y = f[y][i];
            }
        return f[x][0];
    }
    
    inline ll qmax(ll u,ll v,ll maxx)//找最大值(或次大值)-- 倍增的思想 
    {
        ll ans = -INF;
        for(ll i = 18;i >= 0;i--)
        {
            if(deep[f[u][i]] >= deep[v])
            {
                if(maxx != maxi[u][i])
                    ans = max(ans,maxi[u][i]);
                else
                    ans = max(ans,mini[u][i]);
                u = f[u][i];
            }
        }
        return ans;
    }
    
    int main()
    {
        n = read(),m = read();
        for(ll i  = 1;i <= m;i++)
            A[i].u = read(),A[i].v = read(),A[i].d = read();
        sort(A+1,A+m+1,cmp);
        for(ll i = 1;i <= n;i++)
            fa[i] = i;
        ll cnt = 0LL;
        for(ll i = 1;i <= m;i++)//kruscal 
        {
            ll u = getfa(A[i].u);
            ll v = getfa(A[i].v);
            if(u != v)
            {
                cnt += A[i].d;
                fa[u] = v;
                add(A[i].u,A[i].v,A[i].d);
                add(A[i].v,A[i].u,A[i].d);
                vis[i] = true;
            }
        }
        mini[1][0] = -INF;
        deep[1] = 1;
        dfs(1,-1);
        cal();//维护最大值和次大值 
        ll ans = INF;
        for(ll i = 1;i <= m;i++)
        {
            if(!vis[i])//没有被加过边(不在生成图中) 
            {
                ll u = A[i].u;
                ll v = A[i].v;
                ll d = A[i].d;
                ll o = lca(u,v);
                ll maxu = qmax(u,o,d);
                ll maxv = qmax(v,o,d);
                ans = min(ans,cnt - max(maxu,maxv) + d);
            }
        } 
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    导包路径
    django导入环境变量 Please specify Django project root directory
    替换django的user模型,mysql迁移表报错 django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependen cy user.0001_initial on database 'default'.
    解决Chrome调试(debugger)
    check the manual that corresponds to your MySQL server version for the right syntax to use near 'order) values ('徐小波','XuXiaoB','男','1',' at line 1")
    MySQL命令(其三)
    MySQL操作命令(其二)
    MySQL命令(其一)
    [POJ2559]Largest Rectangle in a Histogram (栈)
    [HDU4864]Task (贪心)
  • 原文地址:https://www.cnblogs.com/darlingroot/p/10666595.html
Copyright © 2011-2022 走看看