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 Ai,Bi 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 Ai+1 will be connected by an edge with a weight of Ci+1.
  • The two vertices numbered Ai+1 and Bi+1 will be connected by an edge with a weight of *C**i*+2.
  • The two vertices numbered Bi+1 and Ai+2 will be connected by an edge with a weight of *C**i*+3.
  • The two vertices numbered Ai+2 and Bi+2 will be connected by an edge with a weight of *C**i*+4.
  • The two vertices numbered Bi+2 and Ai+3 will be connected by an edge with a weight of *C**i*+5.
  • The two vertices numbered Ai+3 and Bi+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 
#include 
#include 
#include 
#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

你可能感兴趣的:(Atcoder2134 Zigzag MST)