问题描述
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≦i≦Q) query, three integers Ai,Bi and Ci will be given, and we will add infinitely many edges to the graph as follows:
- The two vertices numbered Ai and Bi will be connected by an edge with a weight of Ci.
- The two vertices numbered Bi 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 Ci+2.
- The two vertices numbered Bi+1 and Ai+2 will be connected by an edge with a weight of Ci+3.
- The two vertices numbered Ai+2 and Bi+2 will be connected by an edge with a weight of Ci+4.
- The two vertices numbered Bi+2 and Ai+3 will be connected by an edge with a weight of Ci+5.
- The two vertices numbered Ai+3 and Bi+3 will be connected by an edge with a weight of Ci+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 figure below shows the first seven edges added when N=16,Ai=7,Bi=14,Ci=1:
After processing all the queries, find the total weight of the edges contained in a minimum spanning tree of the graph.
题目大意:对一张 n 个点的空图 G 做 Q 次加边操作,每次给定 Ai ,Bi ,Ci ,然后按照以下规则按顺序连 10 233 条边:(Ai ,Bi ,Ci ),(Bi ,Ai + 1,Ci + 1),(Ai + 1,Bi + 1,Ci + 2),以此类推,点的编号均为 mod n 意义下的,求图 G 的最小生成树。
输入格式
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.
样例输入
#1
7 1
5 2 1
#2
2 1
0 0 1000000000
#3
5 3
0 1 10
0 2 10
0 4 10
样例输出
#1
21
The figure below shows the minimum spanning tree of the graph:
Note that there can be multiple edges connecting the same pair of vertices.
#2
1000000001
Also note that there can be self-loops.
#3
42
题解
要求一个有无数条边的图的最小生成树,乍一看很吓人,但是乍一想,如果真的是无数条边,再大的空间也存不下。所以肯定有办法可以化无限为有限。
画画图找找规律。
不难发现,加边是有规律的,而且越往后权值越大,也就越不容易被用到。由样例1易发现,由一条边扩展出有限的边数就可以让图连通。那么只要保留让图连通的边就行了。
根据加边的规律,(A,B) 连一条 C 的边,(A,A + i) 连一条 (C + 1 + 2i) 的边,(B,B + i) 连一条 (C + 2 + 2i) 的边。
设di 表示 (i,i + 1) 间的最小权值。
由于一组数据有多组(Ai,Bi,Ci),可能在某条(Ai,Bi,Ci)扩展某条(k,k+1)之前已经有一条(Aj,Bj,Cj)扩展过同一条(k,k+1),则d k= min(dk ,C);
随后再循环di = min(di ,di−1 + 2)。
#include <algorithm> #include <cstdio> #define LL long long struct node{ int u,v; LL w; }g[400005]; int n,m,fa[200005],num; LL d[200005],tot; void add(int x,int y,int z) { g[++num].u=x; g[num].v=y; g[num].w=z; return; } LL min(LL x,LL y) { return x<y?x:y; } bool cmp(node x,node y) { return x.w<y.w; } int find(int x) { if (fa[x]==x) return x; return fa[x]=find(fa[x]); } void Kruskal() { int i,j,k,fu,fv,cnt; for (i=0;i<n;i++) fa[i]=i; std::sort(g+1,g+num+1,cmp); for (i=1;i<=num;i++) { fu=find(g[i].u); fv=find(g[i].v); if (fu!=fv) { fa[fv]=fu; //cnt++; tot+=g[i].w; //if (cnt==n-1) return; } } return; } int main() { int i,j,k,x,y; LL z; scanf("%d%d",&n,&m); for (i=0;i<n;i++) d[i]=1e18; for (i=1;i<=m;i++) { scanf("%d%d%lld",&x,&y,&z); add(x,y,z); if (z+1<d[x]) d[x]=z+1; if (z+2<d[y]) d[y]=z+2; } for (k=1;k<=2;k++) for (i=0;i<n;i++) d[i]=min(d[i],d[(i+n-1)%n]+2); for (i=0;i<n;i++) add(i,(i+1)%n,d[i]); Kruskal(); printf("%lld",tot); return 0; }