zoukankan      html  css  js  c++  java
  • lougu P4180 【模板】严格次小生成树[BJWC2010]

    严格次小生成树 :边权和大于最小生成树
    非严格次小生成树 :边权和大于等于最小生成树
    -----------严格次小生成树----------
    -时间复杂度O(mlog(mn))


    首先求最小生成树,O(mlogm)
    那么次小生成树就是将最小生成树上的一条边换掉


    -正确性
          每换掉一条边,边权和肯定变大
          如果存在改变两条边的最小生成树是严格次小生成树的话,那么只改一条边时边权和肯定小于 改变两条边
          所以选择换掉的边是使边权和增加最小的边

    每次换掉一条边时
    被换掉的边与即将换上的边构成一个环,我们要从这个环上删去一条边,被删去的边在 即将换上的边 的两个节点树上路径里
    被换掉的边一定是可以被换掉的边中边权最大的

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct ll{int x,y,len,vis;} s[300020];
    int head[100005],nxt[200005],to[200005],val[300005],cnt;//val数组开2*10^5+5就会RE的玄学问题 
    int n,m,f[100005][25],maxv[100005][25],max2[100005][25],dep[100005],fa[100005];
    void add(int x,int y,int v)
    {
        cnt++;
        nxt[cnt]=head[x];
        head[x]=cnt;
        to[cnt]=y;
        val[cnt]=v;
    }
    bool cmp(ll a,ll b){return a.len<b.len;}
    long long ans;
    int getfa(int x){return (fa[x]==x)?x:(fa[x]=getfa(fa[x]));}
    void dfs(int x,int fa)//建树 
    {
        f[x][0]=fa;
        for(int i=head[x]; i; i=nxt[i])
        {
            if(to[i]==fa) continue;
            dep[to[i]]=dep[x]+1;
            maxv[to[i]][0]=val[i]; 
            max2[to[i]][0]=-2e9;//防止自环
            dfs(to[i],x);
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=24; i>=0; i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=24; i>=0; i--)
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
        return f[x][0];
    }
    int qiumax(int x,int y,int vall)
    {
        int maxx=-2e9;
        for(int i=24;i>=0&&x!=y;i--)
        {
            if(dep[f[x][i]]>=dep[y])
            {
                if(maxv[x][i]!=vall) maxx=max(maxx,maxv[x][i]);
                else maxx=max(maxx,max2[x][i]);
                x=f[x][i];
            }
        }
        return maxx;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].len);
            s[i].vis=0;
            fa[s[i].x]=s[i].x;
            fa[s[i].y]=s[i].y;
        }
        int k=0;
        sort(s+1,s+m+1,cmp);
        for(int i=1; i<=m; i++)//求最小生成树 
        {
            int fax=getfa(s[i].x),fay=getfa(s[i].y);
            if(fax!=fay)
            {
                ans+=(long long)s[i].len;
                fa[fax]=fay;
                s[i].vis=1;
                k++;
                add(s[i].x,s[i].y,s[i].len);
                add(s[i].y,s[i].x,s[i].len);
                if(k==n-1) break;
            }
        }
        dep[1]=1;
        f[1][0]=-2e9;
        dfs(1,-1);
        for(int i=1; i<=24; i++)     //LCA预处理 
            for(int j=1; j<=n; j++)
            {
                //从j向上走2^i步过程中最长边与次长边一定从maxv[j][i-1],maxv[f[j][i-1]][i-1]与 max2[j][i-1],max2[f[j][i-1]][i-1]中诞生 
                f[j][i]=f[f[j][i-1]][i-1];
                maxv[j][i]=max(maxv[j][i-1],maxv[f[j][i-1]][i-1]);  //从j向上走2^i步过程中最长边 
                max2[j][i]=max(max2[j][i-1],max2[f[j][i-1]][i-1]);  //次长边 
                if(maxv[j][i-1]>maxv[f[j][i-1]][i-1]) max2[j][i]=max(max2[j][i],maxv[f[j][i-1]][i-1]);
                else if(maxv[j][i-1]<maxv[f[j][i-1]][i-1]) max2[j][i]=max(maxv[j][i-1],max2[j][i]);
                
            }
        long long sum=2e16;
        for(int i=1; i<=m; i++)
        {
            if(!s[i].vis)
            {
                int lcca=lca(s[i].x,s[i].y);
                int mxx1=qiumax(s[i].x,lcca,s[i].len); 
                int mxx2=qiumax(s[i].y,lcca,s[i].len);
                sum=min(sum,ans+(long long)s[i].len-(long long)max(mxx1,mxx2));
            }
        }
        printf("%lld",sum);
        return 0;
    }
  • 相关阅读:
    计算一个数的逆序数的个数(1)
    Javascript DOM(2)
    python 装饰器
    Javascript DOM
    Javascrip 入门第三节课
    C# sapnco支持.net 4.5了,真是个意外的发现
    uft调用rfc接口
    pyqt常用窗口组件
    python QQTableView中嵌入复选框CheckBox四种方法
    Pygame模块,功能表
  • 原文地址:https://www.cnblogs.com/QAQq/p/10656939.html
Copyright © 2011-2022 走看看