zoukankan      html  css  js  c++  java
  • Atcoder2134 Zigzag MST

    问题描述

    We have a graph with N vertices, numbered 0 through N−1. Edges are yet to be added.

    We will process Q queries to add edges. In the i-th (1≦iQ) query, three integers A**i,B**i and C**i will be given, and we will add infinitely many edges to the graph as follows:

    • The two vertices numbered A**i and B**i will be connected by an edge with a weight of C**i.
    • The two vertices numbered B**i and A**i+1 will be connected by an edge with a weight of C**i+1.
    • The two vertices numbered A**i+1 and B**i+1 will be connected by an edge with a weight of C**i+2.
    • The two vertices numbered B**i+1 and A**i+2 will be connected by an edge with a weight of C**i+3.
    • The two vertices numbered A**i+2 and B**i+2 will be connected by an edge with a weight of C**i+4.
    • The two vertices numbered B**i+2 and A**i+3 will be connected by an edge with a weight of C**i+5.
    • The two vertices numbered A**i+3 and B**i+3 will be connected by an edge with a weight of C**i+6.
    • ...

    Here, consider the indices of the vertices modulo N. For example, the vertice numbered N is the one numbered 0, and the vertice numbered 2N−1 is the one numbered N−1.

    输入格式

    The input is given from Standard Input in the following format:

    N Q
    A1 B1 C1
    A2 B2 C2
    :
    AQ BQ CQ

    输出格式

    Print the total weight of the edges contained in a minimum spanning tree of the graph.

    样例输入

    7 1
    5 2 1

    样例输出

    21

    解析

    考虑等价替换。对于一次加边操作,由于 (x,y) 的权值比 (y,x+1) 的权值小,考虑kruskal 的过程,在考虑边 (y,x+1,z+1) 的时候,x,y 一定已在一个连通块里。于是,我们可以将 (y,x+1,z+1) 等价替换为 (x,x+1,z+1)。同理,(x+1,y+1,z+2) 可替换为(y,y+1,z+2)。经过这样的替换后,我们发现,一次加边操作会使图上产生两个环,以a为起点的环的路径为c+1,c+3,c+5,......,以b为起点的环的路径为c+2,c+4,c+6,......,同时还有(a,b,c)的边。设(f[i])表示从i-1到i之间的边中最小的,我们可以用类似于最大前缀的方式,求出每一个f:

    [f[i+1]=max(f[i+1],f[i]) ]

    注意(f[n+1]=f[1]),因为在更新一圈后可能还有可以被后来的点更新的,所以我们要更新两圈。

    最后,图中只剩下q+n条边,用Kruskal求最大生成树即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define int long long
    #define N 400002
    using namespace std;
    struct edge{
    	int u,v,w;
    }e[N];
    int n,q,i,f[N],num,fa[N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    int my_comp(const edge &x,const edge &y)
    {
    	return x.w<y.w;
    }
    int find(int x)
    {
    	if(x!=fa[x]) fa[x]=find(fa[x]);
    	return fa[x];
    }
    int Kruscal()
    {
    	for(int i=1;i<=n;i++) fa[i]=i;
    	sort(e+1,e+num+1,my_comp);
    	int cnt=n,ans=0;
    	for(int i=1;i<=num;i++){
    		int f1=find(e[i].u),f2=find(e[i].v);
    		if(f1!=f2){
    			fa[f1]=f2;
    			cnt--;
    			ans+=e[i].w;
    		}
    	}
    	return ans;
    }
    signed main()
    {
    	memset(f,0x3f,sizeof(f));
    	n=read();q=read();
    	for(i=1;i<=q;i++){
    		int a,b,c;
    		a=read()+1;b=read()+1;c=read();
    		e[++num]=(edge){a,b,c};
    		f[a]=min(f[a],c+1);
    		f[b]=min(f[b],c+2);
    	}
    	bool flag=0;
    	for(i=1;i<=n;i++){
    		f[i%n+1]=min(f[i]+2,f[i%n+1]);
    		if(i==n&&!flag) i=0,flag=1;
    	}
    	for(i=1;i<=n;i++) e[++num]=(edge){i,i%n+1,f[i]};
    	cout<<Kruscal()<<endl;
    	return 0;
    }
    
  • 相关阅读:
    ps命令详解
    要做linux运维工程师的朋友,必须要掌握以下几个工具才行 ...
    Centos IP、DNS设置
    查看服务器 硬件参数命令(持续更新)
    Linux系统下配置短信猫
    vimrc 设置
    linux关于bashrc与profile的区别(转)
    Unix 设计哲学基础
    13年计算机真题
    华为卓越工作法读后感
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11183991.html
Copyright © 2011-2022 走看看