• 【Beijing 2010】 次小生成树


    【题目链接】

                点击打开链接

    【算法】

               首先,有一个结论 : 一定有一棵严格次小生成树是在最小生成树的基础上去掉一条边,再加上一条边

               这个结论的正确性是显然的

               我们先用kruskal算法求出最小生成树,然后,枚举不在最小生成树上的边,我们发现若加上这条边,

               则形成了一个环,用最小生成树的权值和加上这条边的权值再减去在这个环上且在最小生成树上权值

               最大的边即为包括这条边的最小生成树的权值和

               那么,树上倍增可以解决这个问题

               因为是要求严格最小,所以我们不仅要记录最大值,还要记录次大值

              时间复杂度 : O((N+M)log(N))

    【代码】

              注意使用long long,INF开到10^18!

             

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100010
    #define MAXM 300010
    #define MAXLOG 20
    const long long INF = 1e18;
    
    struct info
    {
            int x,y;
            long long w;
    } edge[MAXM];
    struct Edge
    {
            int to;
            long long w;
            int nxt;
    } e[MAXM<<1];
    
    int i,n,m,tot;
    int fa[MAXN],head[MAXN],dep[MAXN],anc[MAXN][MAXLOG];
    long long ans = INF,val;
    long long mx[MAXN][MAXLOG],nx[MAXN][MAXLOG];
    bool on_mst[MAXM];
     
    inline bool cmp(info a,info b) { return a.w < b.w; }
    inline int get_root(int x)
    {
            if (fa[x] == x) return x;
            return fa[x]  = get_root(fa[x]);
    }
    inline void add(int x,int y,int w)
    {
            tot++;
            e[tot] = (Edge){y,w,head[x]};
            head[x] = tot;
    }
    inline void kruskal()
    {
            int i,sx,sy;
            long long x,y,w;
            for (i = 1; i <= n; i++) fa[i] = i;
            for (i = 1; i <= m; i++) on_mst[i] = false;
            sort(edge+1,edge+m+1,cmp);
            for (i = 1; i <= m; i++)
            {
                    x = edge[i].x;
                    y = edge[i].y;
                    w = edge[i].w;
                    sx = get_root(x);
                    sy = get_root(y);
                    if (sx != sy)
                    {
                            val += w;
                            fa[sx] = sy;
                            on_mst[i] = true;
                            add(x,y,w);
                            add(y,x,w);
                    }
            }
    }
    inline void dfs_init(int u)
    {
            int i,v;
            for (i = 1; i < MAXLOG; i++)
            {
                    if (dep[u] < (1 << i)) break;
                    anc[u][i] = anc[anc[u][i-1]][i-1];
                    mx[u][i] = max(mx[u][i-1],mx[anc[u][i-1]][i-1]);
                    if (mx[u][i-1] == mx[anc[u][i-1]][i-1]) nx[u][i] = max(nx[u][i-1],nx[anc[u][i-1]][i-1]);
                    else nx[u][i] = max(min(mx[u][i-1],mx[anc[u][i-1]][i-1]),max(nx[u][i-1],nx[anc[u][i-1]][i-1]));
            }
            for (i = head[u]; i; i = e[i].nxt)
            {
                    v = e[i].to;
                    if (anc[u][0] != v)
                    {
                            dep[v] = dep[u] + 1;
                            anc[v][0] = u;
                            mx[v][0] = e[i].w;
                            dfs_init(v);
                    }
            }
    }
    inline long long get(int x,int y,long long w)
    {
            int i,t;
            long long ret = 0;
            if (dep[x] > dep[y]) swap(x,y);
            t = dep[y] - dep[x];
            for (i = 0; i < MAXLOG; i++)
            {
                    if (t & (1 << i))
                    {
                            if (mx[y][i] == w) ret = max(ret,nx[y][i]);
                            else ret = max(ret,mx[y][i]);
                            y = anc[y][i];
                    }
            }
            if (x == y) return ret;
            for (i = MAXLOG - 1; i >= 0; i--)
            {
                    if (anc[x][i] != anc[y][i])
                    {
                            if (mx[x][i] == w) ret = max(ret,nx[x][i]);
                            else ret = max(ret,mx[x][i]);
                            if (mx[y][i] == w) ret = max(ret,nx[y][i]);
                            else ret = max(ret,mx[y][i]);
                            x = anc[x][i];
                            y = anc[y][i];
                    }
            }
            if (mx[x][0] != w) ret = max(ret,mx[x][0]);
            if (mx[y][0] != w) ret = max(ret,mx[y][0]);
            return ret; 
    }
    int main()
    {
        
            scanf("%d%d",&n,&m);
            for (i = 1; i <= m; i++) scanf("%lld%lld%lld",&edge[i].x,&edge[i].y,&edge[i].w);
            kruskal();
            dfs_init(1);
            for (i = 1; i <= m; i++)
            {
                    if (!on_mst[i])
                            ans = min(ans,val+edge[i].w-get(edge[i].x,edge[i].y,edge[i].w));
            }
            printf("%lld
    ",ans);
            
            return 0;
    }
  • 相关阅读:
    CSS优先级及继承
    group by 与 order by
    软件开发升级指南(转)
    安装DELL服务器,安装Windows 2003 sp2 问题
    SQL SERVER 2005数据库总结
    C#操作INI文件(调用WindowsAPI函数:WritePrivateProfileString,GetPrivateProfileString)
    对RBS理解与使用
    WSS和MOSS的区别
    关于.net winform ComboBox数据绑定显示问题
    OpenNETCF.Desktop.Communication.DLL程序集的使用
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196292.html
Copyright © 2020-2023  润新知