• 【XSY2515】管道(pipe)(LCA+最小生成树)


    原题链接


    (Description)

    给你一个城市下水道网络图,你需要选出一些管道,使得在只使用这些管道的情况下,令整个网络联通,并且花费最小。

    网络图可以看做是无向连通图,有(n)个节点和(m)条边,每条边连接(u_{i})(v_{i}),选择的花费是(w_{i})

    不巧的是,由于某些原因,现在市政局要求选定某条特定的边管道,你的任务是求出对于某一条边,在选择这条管道的前提下的最小花费。


    (Input)

    (1)行包含两个整数(n)(m),表示点数和边数。

    (2sim m+1)行每行三个整数(u_{i})(v_{i})(w_{i}),表示有一条管道连接(u_{i})(v_{i}),费用为(w_{i})


    (Output)

    输出(m)行,每行一个整数,表示选择第(i)条管道的前提下的最小花费。

    管道按输入的顺序编号为(1sim m)


    (Sample Input)

    5 7

    1 2 3

    1 3 1

    1 4 5

    2 3 2

    2 5 3

    3 4 2

    4 5 4


    (Sample Output)

    9

    8

    11

    8

    8

    8

    9


    (Hint)

    对于(20\%)的数据,(n<=1000,m<=2000)

    对于另外(20\%)的数据,(m<=n+10)

    对于(100\%)的数据,(2<=n<=100000,1<=m<=200000)

    保证初始图连通


    思路

    这道题其实十分简单

    我们先求出一棵最小生成树

    然后,我们取第(i)条边,易得这条边所在的最小生成树中的其他边都是原最小生成树中的边

    于是,我们可以将(u_{i})(v_{i})上的一些边去掉,为了满足最小,当然要选择最大的边删除

    对于维护最大边,我们考虑用(LCA)倍增维护

    (ps:)不开(long) (long)见祖宗,数组开小见阎王


    #include<bits/stdc++.h>
    using namespace std;
    const long long N=200010;
    long long n,m,tot=0;
    long long fa[N];
    long long f[N][30];
    long long maxn[N][30];
    long long dep[N];
    long long head[N];
    long long ans[N];
    bool vis[N];
    struct road
    {
        long long to,nxt,dis,id;
    }e[N<<1];
    struct edge
    {
        long long u,v,w,id;
    }g[N];
    long long find(long long a)
    {
        if(a==fa[a])return a;
        return fa[a]=find(fa[a]);
    }
    void dfs(long long u)
    {
        for(long long i=1;i<=18;i++)
        {
            f[u][i]=f[f[u][i-1]][i-1];//更新倍增信息
            maxn[u][i]=max(maxn[u][i-1],maxn[f[u][i-1]][i-1]);
        }
        for(long long i=head[u];i;i=e[i].nxt)
        {
            long long v=e[i].to,dis=e[i].dis,idx=e[i].id;
            if(v!=f[u][0])
            {
                f[v][0]=u;
                maxn[v][0]=dis;//维护最大边
                dep[v]=dep[u]+1;
                dfs(v);
            }
        }
    }
    long long get(long long x,long long y)
    {
        long long p=0;
        if(dep[x]<dep[y])swap(x,y);
        for(long long i=18;i>=0;i--)
        {
            if(dep[f[x][i]]>=dep[y])
            {
                p=max(p,maxn[x][i]);//维护最大边
                x=f[x][i];
            }
        }
        if(x==y)return p;
        for(long long i=18;i>=0;i--)
        {
            if(f[x][i]!=f[y][i])
            {
                p=max(p,max(maxn[x][i],maxn[y][i]));//最大边
                x=f[x][i],y=f[y][i];
            }
        }
        return max(p,max(maxn[x][0],maxn[y][0]));
    }
    void add(long long u,long long v,long long w,long long idx)
    {
        e[++tot]=(road){v,head[u],w,idx};head[u]=tot;
        e[++tot]=(road){u,head[v],w,idx};head[v]=tot;
    }
    bool cmp(edge a,edge b)
    {
        return a.w<b.w;
    }
    inline long long read()
    {
    	long long x=0,f=1;
    	char ch=getchar();
    	while(!isdigit(ch))
    	{
    		if(ch=='-')f=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    	{
    		x=(x<<3)+(x<<1)+(ch^48);
    		ch=getchar();
    	}
    	return x*f;
    }
    int main()
    {
    	n=read(),m=read();
        for(long long i=1;i<=m;i++)g[i].u=read(),g[i].v=read(),g[i].w=read(),g[i].id=i;
        sort(g+1,g+m+1,cmp);
        for(long long i=1;i<=n;i++)fa[i]=i;
        long long sum=0;
        for(long long i=1;i<=m;i++)
        {
            long long fx=find(g[i].u);
            long long fy=find(g[i].v);
            if(fx!=fy)
            {
                fa[fy]=fx;
                sum+=g[i].w;
                add(g[i].u,g[i].v,g[i].w,g[i].id);
                vis[i]=1;
            }
        }
        //最小生成树
        dep[1]=1;
        dfs(1);
        for(long long i=1;i<=n;i++)fa[i]=i;
        for(long long i=1;i<=m;i++)
        {
            long long x=g[i].u,y=g[i].v,z=g[i].w,idx=g[i].id;
            if(vis[i])//如果在原最小生成树中
            {
            	ans[idx]=sum;
            	continue;
    		}
    		long long summ=get(x,y);
    		ans[idx]=sum+g[i].w-summ;//原最小生成树加上这条边权值再减去边上最大值
        }
        for(long long i=1;i<=m;i++)printf("%lld
    ",ans[i]);
        return 0;
    }
    /*
    5 7
    
    1 2 3
    
    1 3 1
    
    1 4 5
    
    2 3 2
    
    2 5 3
    
    3 4 2
    
    4 5 4
    */
    
  • 相关阅读:
    面试问题总结
    2016后半年读书系统
    java基础知识
    自动化测试的误区
    软件测试的艺术
    QTP
    软件测试的艺术读书笔记
    Jquery中$(document).ready()
    Python爬取糗事百科示例代码
    【转载】气象数据相关资源
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11397004.html
Copyright © 2020-2023  润新知