zoukankan      html  css  js  c++  java
  • BZOJ 1977 [BeiJing2010组队]次小生成树 Tree

    严格次小生成树。一开始没有特批一圈都相等的情况,一直WA,十分难受。

    先生成最小生成树,枚举每条非树边,连上它构成一个环,拆掉环上树边中最大的一条(若和该边相等则次大的一条)换上这条。

    用倍增维护一条链上的最大边和次大边,倍增跑lca同时找出环上最大边和次大边,看能否更新答案。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    typedef long long LL;
    using namespace std;
    const int maxn=100000+299;
    const int maxm=300000*2+299;
    int upp=0,tot,n,m,k,ecnt,fir[maxn],nxt[maxm],to[maxm],vis[maxn],fa[maxn];
    int f[maxn][32],R[maxn]; 
    LL st[maxn][32],stc[maxn][32],ans,rem,rec,val[maxm],anspre;
    struct edge{
        int u,v,w,is;
        friend bool operator <(const edge&A,const edge&B) {
            return A.w<B.w;
        }
    }e[maxm];
    void add(int u,int v,int w) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=(LL)w;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=(LL)w;
    }
    void init() {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) 
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    }
    int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
    void kruskal() {
        sort(e+1,e+m+1);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++) {
            int u=e[i].u,v=e[i].v;
            int fu=find(u),fv=find(v);
            if(fu!=fv) {
                e[i].is=1;
                anspre+=e[i].w;
                add(u,v,e[i].w);
                tot++;
                if(tot==n-1) break;
                fa[fu]=fv;
            }
        }
    }
    void dfs(int x,int ff) {
        f[x][0]=ff; R[x]=R[ff]+1;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=ff){
            st[to[i]][0]=val[i];
            stc[to[i]][0]=val[i];
            dfs(to[i],x);
        }
    }
    void make_st() {
        for(int i=1;i<=30;i++)
            for(int j=1;j<=n;j++) {
                f[j][i]=f[f[j][i-1]][i-1];
                int u=st[j][i-1],v=st[f[j][i-1]][i-1];
                st[j][i]=max(u,v);    
                if(u&&v&&u!=v) stc[j][i]=min(u,v);
                if(stc[j][i-1]) stc[j][i]=max(stc[j][i],stc[j][i-1]);
                if(stc[f[j][i-1]][i-1]) stc[j][i]=max(stc[j][i],stc[f[j][i-1]][i-1]);
            }
    }
    int swapp(LL x,LL &zd,LL &cd) {
        if(x==zd) return 0;
        if(x>zd) {
            cd=max(cd,zd);
            zd=x;
        }
        else cd=max(cd,x);
    }
    int lca(int x,int y) {
        rem=0,rec=0;
        if(R[x]<R[y]) swap(x,y);
        for(int i=30;i>=0;i--) {
            if(R[f[x][i]]>=R[y]) { 
                if(rem&&st[x][i]>rem) rec=max(rem,rec);
                rem=max(rem,st[x][i]);
                if(i!=0) rec=max(rec,stc[x][i]);
                x=f[x][i]; 
            }
        }
        if(x==y) return 1;
        for(int i=30;i>=0;i--) {
            if(f[x][i]!=f[y][i]) {
                swapp(stc[y][i],rem,rec);
                swapp(stc[x][i],rem,rec);
                swapp(st[x][i],rem,rec);
                swapp(st[y][i],rem,rec);
                x=f[x][i]; y=f[y][i];
            }
        }
        swapp(stc[y][0],rem,rec);
        swapp(stc[x][0],rem,rec);
        swapp(st[x][0],rem,rec);
        swapp(st[y][0],rem,rec);
        return 1;
    }
    void work() {
        ans=1e18;
        for(int i=1;i<=m;i++) if(e[i].is!=1){
            int x=e[i].u,y=e[i].v;
            lca(x,y);
            if(e[i].w!=rem) ans=min(ans,anspre-rem+e[i].w);
            else if(e[i].w!=rec) ans=min(ans,anspre-rec+e[i].w);
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        init();
        kruskal();
        dfs(1,0);
        make_st();
        work();
        return 0;
    }
    View Code

     

  • 相关阅读:
    ASP.NET大闲话:ashx文件有啥用
    Silverlight之我见——制作星星闪烁动画
    今天写了一个简单的新浪新闻RSS操作类库
    继续聊WPF——设置网格控件列标题的样式
    继续聊WPF——如何获取ListView中选中的项
    继续聊WPF——Thumb控件
    继续聊WPF——进度条
    继续聊WPF——自定义CheckBox控件外观
    继续聊WPF——Expander控件(1)
    继续聊WPF——Expander控件(2)
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7565327.html
Copyright © 2011-2022 走看看