【AtCoder】[CODE FESTIVAL 2016 Final G] Zigzag MST

相关链接

题目传送门:http://cf16-final.contest.atcoder.jp/tasks/codefestival_2016_final_g
官方题解:http://oi.cyo.ng/wp-content/uploads/2017/01/atcoder_codefestival_2016_final_g.pdf

解题报告

这题好神啊!现在感觉每道题都好神啊!

先来看任意一个连边操作:

考虑正常的最小生成树算法,如果用到了价值为 $ c+1$ 的边,那么价值为 $ c$ 的边一定已经考虑过了
于是我们就可以把图等价地变换为下面这个样子:

这样的话,我们可以把价值为 $ c$ 地那一类边拿出来单独考虑
余下的边搞一个堆,连一圈
这样的话,我们的图就改造成了这个样子:

此时我们的边就只剩 $ N+Q$ 条了,直接跑最小生成树算法就可以啦!

Code

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 400000+9;

struct Edge{int u,v,w;}e[N];
struct Operation{int p,c;}op[N];
priority_queue<Operation> que;
int n,m,tot,vis[N],fa[N]; LL vout;

inline bool operator < (const Edge &A, const Edge &B) {return A.w < B.w;}
inline bool operator < (const Operation &A, const Operation &B) {return A.c > B.c;}

inline int read() {
	char c=getchar(); int f=1,ret=0;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
	return ret * f;
}

inline int find(int w) {
	int f = fa[w], tmp;
	while (f != fa[f]) f = fa[f];
	while (w != f) tmp = fa[w], fa[w] = f, w = tmp;
	return f;
}

int main() {
	n = read(); m = read();
	for (int i=1,a,b,c;i<=m;i++) {
		a = read(); b = read(); c = read();
		e[++tot] = (Edge){a, b, c};
		que.push((Operation){a, c+1});
		que.push((Operation){b, c+2});
	}
	while (!que.empty()) {
		Operation w = que.top(); que.pop();
		if (!vis[w.p]) {
			vis[w.p] = 1;
			e[++tot] = (Edge){w.p, (w.p+1)%n, w.c};
			que.push((Operation){(w.p+1)%n, w.c+2});
		}
	}
	sort(e+1, e+1+tot);
	for (int i=0;i<=n;i++) fa[i] = i;
	for (int i=1;i<=tot;i++) {
		if (find(e[i].u) != find(e[i].v)) {
			fa[fa[e[i].u]] = fa[e[i].v];
			vout += e[i].w;
		}
	}
	printf("%lld\n",vout);
	return 0;
}

175 thoughts to “【AtCoder】[CODE FESTIVAL 2016 Final G] Zigzag MST”

Leave a Reply

Your email address will not be published. Required fields are marked *