码迷,mamicode.com
首页 > 其他好文 > 详细

[CF609E]Minimum spanning tree for each edge

时间:2018-10-09 20:02:48      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:最小生成树   print   struct   printf   last   col   imu   lld   nbsp   

题目大意:有一张$n$个点$m$条边的图,要求对于每条边求出包含这条边的最小生成树

题解:先求出最小生成树,发现加入一条不在最小生成树上的边,就会出现一个环,那么把这个环上除这条边外权值最大的一条边删去就是对于这条边的最小生成树,可以倍增求

卡点:倍增结尾处理错

 

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 200010

int head[maxn], cnt;
struct Edge {
	int to, nxt, w;
} e[maxn << 1];
inline void add(int a, int b, int c) {
	e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
	e[++cnt] = (Edge) {a, head[b], c}; head[b] = cnt;
}

int l[maxn], r[maxn], w[maxn], rnk[maxn];
bool yes[maxn];
inline bool cmp(int a, int b) {return w[a] < w[b];}

int f[maxn];
int find(int x) {return (x == f[x] ? x : (f[x] = find(f[x])));}
int n, m;
long long ans;
#define M 18
int fa[M][maxn], S[M][maxn], dep[maxn];
inline int max(int a, int b) {return a > b ? a : b;}
void dfs(int u) {
	for (int i = 1; i < M; i++) {
		fa[i][u] = fa[i - 1][fa[i - 1][u]];
		S[i][u] = max(S[i - 1][u], S[i - 1][fa[i - 1][u]]);
	}
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa[0][u]) {
			fa[0][v] = u;
			dep[v] = dep[u] + 1;
			S[0][v] = e[i].w;
			dfs(v);
		}
	}
}
inline ask(int x, int y) {
	int res = 0;
	if (dep[x] < dep[y]) std::swap(x, y);
	for (int i = dep[x] - dep[y]; i; i &= i - 1) res = max(res, S[__builtin_ctz(i)][x]), x = fa[__builtin_ctz(i)][x];
	if (x == y) return res;
	for (int i = M - 1; ~i; i--) if (fa[i][x] != fa[i][y]) {
		res = max(res, max(S[i][x], S[i][y]));
		x = fa[i][x], y = fa[i][y];
	}
	return max(res, max(S[0][x], S[0][y]));
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d", l + i, r + i, w + i);
		rnk[i] = i;
	}
	for (int i = 1; i <= n; i++) f[i] = i;
	std::sort(rnk, rnk + m, cmp);
	for (int j = 0, i, lastnum = n - 1; j < m && lastnum; j++) {
		i = rnk[j];
		int u = find(l[i]), v = find(r[i]);
		if (u != v) {
			add(l[i], r[i], w[i]);
			yes[i] = true;
			f[u] = v;
			lastnum--;
			ans += w[i];
		}
	}
	dep[1] = 1;
	dfs(1);
	for (int i = 0; i < m; i++) {
		if (yes[i]) printf("%lld\n", ans);
		else printf("%lld\n", ans - ask(l[i], r[i]) + w[i]);
	}
	return 0;
}

  

[CF609E]Minimum spanning tree for each edge

标签:最小生成树   print   struct   printf   last   col   imu   lld   nbsp   

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9762235.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!