• 严格次小生成树 最小生成树+树上倍增


    严格次小生成树

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

    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

  • 相关阅读:
    Domain Model
    linux 后台运行命令
    morphia(3)-查询
    [八省联考2018] 劈配
    [BZOJ 3218] a+b Problem
    [学习笔记] KM算法
    [HNOI2013] 消毒
    [HNOI2014] 画框
    [HDU 6057] Kanade's convolution
    [模板] 任意模数多项式乘法
  • 原文地址:https://www.cnblogs.com/Bhllx/p/10617109.html
Copyright © 2020-2023  润新知