zoukankan      html  css  js  c++  java
  • 严格次小生成树 最小生成树+树上倍增

    严格次小生成树

    一定要注意是严格次小!!。。。

    Solution:

    相信大家不难想到:

    先做一遍最小生成树,然后枚举剩下的边,然后在树上倍增,把最大的那条边给去掉,把这条给加上,全局取min。

    然后你会发现你开心的交完后,只有80。

    I:诶诶诶,怎么回事,明明是没错的啊。再看看。。。
    
    某神ben:你好呆( ̄_, ̄ )看了题目没。。。
    
    I:略略略,溜了溜了。。
    

    好吧,这个题唯一需要注意的就是:严格次小!严格次小!严格次小!

    这意味着:

    不仅需要维护最大值的倍增数组,还需要维护次大值的倍增数组。

    Code↓:

    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define RG register
    #define IL inline
    #define LL long long
    #define DB double
    using namespace std;
    
    IL int gi() {
        char ch=getchar(); RG int x=0,w=0;
        while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
        while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
        return w?-x:x;
    }
    
    const int N=1e5+10;
    const int M=3e5+10;
    
    LL sum,Ans=1e18;
    int n,m,tot,head[N],fa[N],tag[M],dep[N],f[N][21],g[N][21],t[N][21];
    
    struct Edge{int x,y,z;}e[M];
    struct EDGE{int next,to,v;}E[N<<1];
    
    IL bool cmp(Edge A,Edge B) {return A.z<B.z;}
    
    IL void make(int a,int b,int c) {
        E[++tot]=(EDGE){head[a],b,c},head[a]=tot;
        E[++tot]=(EDGE){head[b],a,c},head[b]=tot;
    }
    
    IL int getfa(int x) {return x==fa[x]?x:fa[x]=getfa(fa[x]);}
    
    IL void Kruskal() {
        RG int i,x,y,fx,fy,num=0;
        sort(e+1,e+m+1,cmp);
        for (i=1;i<=n;++i) fa[i]=i;
        for (i=1;i<=m;++i) {
            x=e[i].x,y=e[i].y,fx=getfa(x),fy=getfa(y);
            if (fx!=fy) {
                tag[i]=1,fa[fx]=fy,sum+=e[i].z,make(x,y,e[i].z);
                if (++num==n-1) break; 
            }
        }
    }
    
    void dfs(int x,int fx) {
        RG int i,y;
        for (i=head[x],dep[x]=dep[fx]+1;i;i=E[i].next)
            if ((y=E[i].to)!=fx) f[y][0]=x,g[y][0]=E[i].v,dfs(y,x);
    }
    
    IL void work() {
        RG int i,j,p;
        for (i=1;i<=20;++i)
            for (j=1;j<=n;++j) {
                p=f[j][i-1],f[j][i]=f[p][i-1];
                if (g[j][i-1]>g[p][i-1]) g[j][i]=g[j][i-1],t[j][i]=max(g[p][i-1],t[j][i-1]);
                if (g[j][i-1]<g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(g[j][i-1],t[p][i-1]);
                if (g[j][i-1]==g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(t[j][i-1],t[p][i-1]);
            }
    }
    
    IL int getMax(int x,int y,int ver) {
        RG int i,ans=0;
        if (dep[x]<dep[y]) swap(x,y);
        for (i=20;i>=0;--i)
            if (dep[f[x][i]]>=dep[y]) {
                if (g[x][i]<ver) ans=max(ans,g[x][i]);
                x=f[x][i];
            } 
        if (x==y) return ans;
        for (i=20;i>=0;--i)
            if (f[x][i]!=f[y][i]) {
                if (g[x][i]<ver) ans=max(ans,g[x][i]);
                if (g[y][i]<ver) ans=max(ans,g[y][i]);
                x=f[x][i],y=f[y][i];
            }
        if (g[x][0]<ver) ans=max(ans,g[x][0]);
        if (g[y][0]<ver) ans=max(ans,g[y][0]);
        return ans;
    }
    
    int main()
    {
        RG int i,now;
        n=gi(),m=gi();
        for (i=1;i<=m;++i) e[i].x=gi(),e[i].y=gi(),e[i].z=gi();
        Kruskal(),dfs(1,0),work();
        for (i=1;i<=m;++i)
            if (!tag[i]) {
                now=getMax(e[i].x,e[i].y,e[i].z);
                Ans=min(Ans,sum+e[i].z-now);
            }
        printf("%lld
    ",Ans);
        return 0;
    }
    
    // 严格次小 不能相等啊...
    
    

    The End

  • 相关阅读:
    一行代码更改博客园皮肤
    fatal: refusing to merge unrelated histories
    使用 netcat 传输大文件
    linux 命令后台运行
    .net core 使用 Nlog 配置文件
    .net core 使用 Nlog 集成 exceptionless 配置文件
    Mysql不同字符串格式的连表查询
    Mongodb between 时间范围
    VS Code 使用 Debugger for Chrome 调试vue
    css权重说明
  • 原文地址:https://www.cnblogs.com/Bhllx/p/10617109.html
Copyright © 2011-2022 走看看