zoukankan      html  css  js  c++  java
  • [树上倍增][最小生成树]JZOJ P4313——电话线铺设

    Description
    这里写图片描述
    Input
    这里写图片描述

    Output

    这里写图片描述

    Sample Input

    6 9 4
    6 3 4
    2 5 6
    5 4 6
    1 3 5
    3 5 9
    5 6 8
    4 1 5
    4 6 4
    6 2 7
    2 5 3
    1 5 4
    4 5 4
    3 2 5

    Sample Output

    22
    1
    8
    4
    3
    1

    Data Constraint
    这里写图片描述

    题解

    我们先对全部的“王牌电缆”建一颗最小生成树
    那么对于要加如来的一条“李牌电缆”,一定会使最小生成树形成一个环(除数据12、13点外)
    如果要使最后得出来的解最小,那么就是要删掉在加入该条“李牌电缆”后形成环上最大的边
    那么我们如果找到这个环?
    易得,如果连接“李牌电缆”两点的最近公共祖先,和这两个点围成的就是要求得的环
    那么,我们可以用倍增求Lca,可支持O(log n),询问两点之间的费用最大的边权
    (Tips:
        如果存在只用“王牌电缆”无法联通整个小区的数据
        直接枚举加入最小生成数里
        取最小值输出
    )
    

    拓展 :树上倍增求LCA

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=800007;
    const int inf=0x7fffffff;
    int l,t,n,m,w,e,num,x,y,z,mn,mnn,mnm;
    int father[maxn],ans,first[maxn],next[maxn],last[maxn],total,zhi[maxn];
    int x1[maxn],y1[maxn],z1[maxn],f[maxn][20],k[maxn][20],aa,g[maxn][20],xu[maxn];
    int ans1[maxn],bb,deep[maxn];
    struct edge{int v,d,l,r;}a[maxn];
    bool cmp(edge x,edge y){ return (x.v<y.v)||(x.v==y.v&&x.l<y.l)||(x.v==y.v&&x.l==y.l&&x.r<y.r); }
    int getfather(int x)
    {
        if (!father[x]) return x;
        father[x]=getfather(father[x]); 
        return father[x];
    }
    void insert(int x,int y,int z,int d)
    {
        last[++total]=y;
        next[total]=first[x];
        first[x]=total;
        zhi[total]=z; 
        xu[total]=d;
        last[++total]=x;
        next[total]=first[y];
        first[y]=total;
        zhi[total]=z;
        xu[total]=d;
    }
    void dfs(int x,int y)
    {
        f[x][0]=y; deep[x]=deep[y]+1;
        for (int i=first[x];i;i=next[i])
            if (last[i]!=y)
            {
                dfs(last[i],x);
                k[last[i]][0]=zhi[i];
                g[last[i]][0]=xu[i];
            }
    }
    int lca(int x,int y)
    {
        int w=0;
        if (deep[x]<deep[y]) swap(x,y);
        for (int i=19;i>=0;i--)
            if (deep[f[x][i]]>deep[y])
            {
                bb=(k[x][i]>w?g[x][i]:bb);
                w=max(w,k[x][i]);
                x=f[x][i];
            }
        if (deep[x]!=deep[y])
        {
            bb=(k[x][0]>w?g[x][0]:bb);
            w=max(w,k[x][0]);
            x=f[x][0];
        }
        for (int i=19;i>=0;i--) 
            if(f[x][i]!=f[y][i]) 
            {
                bb=(k[x][i]>w?g[x][i]:bb);
                w=max(w,k[x][i]);
                bb=(k[y][i]>w?g[y][i]:bb);
                w=max(w,k[y][i]);
                x=f[x][i];
                y=f[y][i];
            }
        if (x!=y) 
        {
            bb=(k[x][0]>w?g[x][0]:bb);
            w=max(w,k[x][0]);
            bb=(k[y][0]>w?g[y][0]:bb);
            w=max(w,k[y][0]);
        }
        aa=w;
        if (x!=y) return f[x][0]; else return x;
    }
    int main()
    {
        freopen("telephone.in","r",stdin);
        freopen("telephone.out","w",stdout);
        scanf("%d%d%d",&n,&w,&l);
        for (int i=1;i<=w;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if (x>y) swap(x,y);
            a[++num].l=x; a[num].r=y; a[num].v=z; a[num].d=i;
        }
        sort(a+1,a+num+1,cmp);
        for (int i=1;i<=l;i++) scanf("%d%d%d",&x1[i],&y1[i],&z1[i]);
        mn=inf;
        for (int i=1;i<=num;i++)
        {
            x=getfather(a[i].l); y=getfather(a[i].r);
            if (x!=y)
            {
                father[y]=x; 
                m++;
                ans+=a[i].v;
                ans1[m]=a[i].d;
                insert(a[i].l,a[i].r,a[i].v,a[i].d);
            }
            if (m==n-1) break;
        }
        if (m==n-2)
        {
            for (int i=1;i<=l;i++)
            {
                x=getfather(x1[i]); y=getfather(y1[i]);
                if (x!=y&&z1[i]<mn)
                {
                    mn=z1[i];
                    mnn=i;
                }
            }
            printf("%d
    ",ans+mn);
            for (int i=1;i<=m;i++) printf("%d
    ",ans1[i]);
            printf("%d
    ",mnn);
            return 0;
        }
        dfs(1,0);
        for (int j=1;j<=19;j++)
            for (int i=1;i<=n;i++)
            {
                f[i][j]=f[f[i][j-1]][j-1];
                if (f[i][j]) g[i][j]=(k[i][j-1]>k[f[i][j-1]][j-1]?g[i][j-1]:g[f[i][j-1]][j-1]);
                if (f[i][j]) k[i][j]=max(k[i][j-1],k[f[i][j-1]][j-1]);
            }
        for (int i=1;i<=l;i++)
        {
            int fa=lca(x1[i],y1[i]);
            if (z1[i]-aa<mn)
            {
                mn=z1[i]-aa;
                mnn=i;
                mnm=bb;
            }
        }
        printf("%d
    ",ans+mn);
        for (int i=1;i<=n-1;i++)
        {
            if (ans1[i]==mnm) continue;
            printf("%d
    ",ans1[i]);
        }
        printf("%d
    ",mnn);
        return 0;
    }
  • 相关阅读:
    [Apple开发者帐户帮助]三、创建证书(2)创建开发者ID证书
    [Apple开发者帐户帮助]三、创建证书(1)证书概述
    [Apple开发者帐户帮助]二、管理你的团队(7)管理服务器帐户
    [Apple开发者帐户帮助]二、管理你的团队(6)找到您的团队ID
    [Apple开发者帐户帮助]二、管理你的团队(5)转移帐户持有人角色
    关于 width;height
    websql
    real-time application
    node
    geolocation
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412239.html
Copyright © 2011-2022 走看看