zoukankan      html  css  js  c++  java
  • 求次小生成树(洛谷P4180&bzoj1977)

    题意:求严格次小生成树(就是不能等于) 思路:先求一个最小生成树 枚举每条非树边 若连入则一定会成环
    那么在这个环中 删去最大的边(除非树边) 就是一个次小生成树
    但是如果那个最大边和非树边的值相等 有可能次小生成树的值就和最小生成树一样
    显然是不成立的 所以应该记录一下次大值 最大值不满足就用次大值
    注意:在dfs中转移的顺序

    /*
    题意:求严格次小生成树(就是不能等于) 
    思路:先求一个最小生成树 枚举每条非树边 若连入则一定会成环
    那么在这个环中 删去最大的边(除非树边) 就是一个次小生成树
    但是如果那个最大边和非树边的值相等 有可能次小生成树的值就和最小生成树一样
    显然是不成立的 所以应该记录一下次大值 最大值不满足就用次大值
    注意:在dfs中转移的顺序 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 100005
    #define ll long long
    struct node{
        int x,y,in; int w;
    }a[N*3];
    int fa[N],head[N<<1],nex[N<<1],to[N<<1],tot=0,f[N][22],dep[N];
    int d1[N][22],d2[N][22],w[N<<1],mn=0x7f7f7f;
    bool cmp(const node &a,const node &b) { return a.w<b.w; }
    int get(int x)
    {
        if(x==fa[x]) return x;
        return fa[x]=get(fa[x]);
    }
    void add(int a,int b,int ww){ to[++tot]=b; nex[tot]=head[a]; head[a]=tot; w[tot]=ww;}
    void dfs(int u,int father)
    {//倍增的初始化一定要在for的外面!! 
        for(int i=1;i<=20;i++){
            f[u][i]=f[f[u][i-1]][i-1];
            //d1是最大值 d2是次大值 
            d1[u][i]=max(d1[u][i-1],d1[f[u][i-1]][i-1]);
            if(d1[u][i-1]==d1[f[u][i-1]][i-1])//最大值相等 次大值就是从两段的次大值转移过来 
                d2[u][i]=max(d2[u][i-1],d2[f[u][i-1]][i-1]);
            else{//不相等就可能由两段最大值中的较小值 或 两段次大值 转移过来 
                d2[u][i]=min(d1[u][i-1],d1[f[u][i-1]][i-1]);
                d2[u][i]=max(d2[u][i],d2[u][i-1]);
                d2[u][i]=max(d2[u][i],d2[f[u][i-1]][i-1]);
            }
        }
        for(int j=head[u];j;j=nex[j]){
            int v=to[j];
            if(v==father) continue;
            dep[v]=dep[u]+1; f[v][0]=u; d1[v][0]=w[j];
            dfs(v,u);
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;i--)
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }//求路径的最大值和次大值 
    void solve(int x,int y,int v)
    {
        int mx1=0,mx2=0;
        int t=dep[x]-dep[y];//深度差 是i的范围 
        for(int i=0;i<=20;i++)
        if(t&(1<<i)){//如果还可以跳 
            if(d1[x][i]>mx1) mx2=mx1,mx1=d1[x][i];
            else mx2=max(mx2,d1[x][i]);
            mx2=max(mx2,d2[x][i]);
            x=f[x][i];
        }
        if(mx1!=v) mn=min(mn,v-mx1);
        else mn=min(mn,v-mx2);
    }
    void work(int x,int y,int ww)
    {
        int lc=lca(x,y); 
        solve(x,lc,ww); solve(y,lc,ww);
    }
    ll ans=0;
    int main()
    {
        int n,m,cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
        sort(a+1,a+1+m,cmp);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++){
            int f1=get(a[i].x),f2=get(a[i].y);
            if(f1!=f2){
                cnt++;
                ans+=a[i].w;
                a[i].in=1;
                fa[f1]=f2;
                add(a[i].x,a[i].y,a[i].w); add(a[i].y,a[i].x,a[i].w);
            }
            if(cnt==n-1) break;
        }
        dfs(1,0);
        for(int i=1;i<=m;i++) if(!a[i].in) work(a[i].x,a[i].y,a[i].w);
        printf("%lld
    ",ans+mn);
    }
    /*
    5 6
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6 
    */
  • 相关阅读:
    Python学习资料
    异常
    I/O
    Python3+迭代器与生成器
    python标准数据类型
    人工智能、机器学习和深度学习
    原地排序和复制排序
    序列化和Json
    登陆加密小程序
    hashlib模块加密用法
  • 原文地址:https://www.cnblogs.com/mowanying/p/11171067.html
Copyright © 2011-2022 走看看