zoukankan      html  css  js  c++  java
  • [题解] CF609E Minimum spanning tree for each edge

    前言

    题目链接:洛谷

    题目链接:CodeForces

    题意

    给你 (n) 个点, (m) 条边,如果对于一个最小生成树中要求必须包括第 (i(1<=i<=m)) 条边,那么最小生成树的权值总和最小是多少。

    思路

    首先求出该图的最小生成树。最小生成树的边的答案就是最小生成树的权值和。记录下来这个权值和,记为 (ans)

    考虑必须包含不在生成树中的边,强行加入了最小生成树对于答案的影响。

    就相当于现将这条边加入生成树中,然后再跑 kruskal ,需要找到被并查集查到相同的父亲的那条边,且这条边在最小生成树内。

    可以发现,直接在生成树中加入这条边形成的环,都有可能受这条边的影响。

    由于按照 kruskal 的思想,边是被排了序的,影响到的边,只有权值最大的一条。

    于是可以维护不带修改的树上路径最大值。用LCA或者树剖+ST表/线段树都可以维护。

    Code

    开了long long 就不会死。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define LL long long
    const int MAXN = 2e5 + 5;
    struct Edge {
    	int To, Dis, Next;
    };
    int head[MAXN], tot = 1;
    Edge edge[MAXN << 1];
    void Addedge(int u, int v, int w) {
    	edge[++tot].Next = head[u], edge[tot].To = v, edge[tot].Dis = w, head[u] = tot;
    	edge[++tot].Next = head[v], edge[tot].To = u, edge[tot].Dis = w, head[v] = tot;
    }
    struct Edge1 {
    	int u, v, w, id;
    	friend bool operator < (Edge1 x, Edge1 y) {
    		return x.w < y.w;
    	}
    };
    Edge1 e[MAXN];
    int dp[MAXN][40], maxn[MAXN][40];
    int fa[MAXN], dep[MAXN], n, m;
    bool flag[MAXN];
    LL ans;
    int Find(int x) {
    	return fa[x] == x ? x : (fa[x] = Find(fa[x]));
    }
    void Union(int x, int y) {
    	fa[Find(x)] = fa[Find(y)];
    }
    int Maxpast(int x, int y) {
    	int res = 0;
    	if (x == y) return res;
    	if (dep[x] < dep[y])
    		swap(x, y);
    	for (int i = 30; i >= 0; i--) {
    		if (dep[x] - (1 << i) >= dep[y]) {
    			res = max(res, maxn[x][i]);
    			x = dp[x][i];
    		}
    	}
    	if (x == y) return res;
    	for (int i = 30; i >= 0; i--) {
    		if (dp[x][i] != dp[y][i]) {
    			res = max(res, max(maxn[x][i], maxn[y][i]));
    			x = dp[x][i];
    			y = dp[y][i];
    		}
    	}
    	res = max(res, max(maxn[x][0], maxn[y][0]));
    	return res;
    }
    void dfs(int u, int fa) {
    	dp[u][0] = fa;
    	dep[u] = dep[fa] + 1;
    	for (int i = head[u]; i; i = edge[i].Next) {
    		int v = edge[i].To;
    		if (v == fa) continue;
    		dfs(v, u);
    		maxn[v][0] = edge[i].Dis;
    	}
    }
    bool cmp(Edge1 x, Edge1 y) {
    	return x.id < y.id;
    }
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
    		e[i].id = i;
    	}
    	for (int i = 1; i <= n; i++)
    		fa[i] = i;
    	sort(e + 1, e + 1 + m);
    	for (int i = 1; i <= m; i++) {
    		int u = Find(e[i].u), v = Find(e[i].v);
    		if (u == v) continue;
    		Union(u, v);
    		ans += e[i].w;
    		flag[e[i].id] = 1;
    		Addedge(e[i].u, e[i].v, e[i].w);
    	}
    	dfs(1, 0);
    	for (int j = 1; j <= 30; j++) {
    		for (int i = 1; i <= n; i++) {
    			dp[i][j] = dp[dp[i][j - 1]][j - 1];
    			maxn[i][j] = max(maxn[i][j - 1], maxn[dp[i][j - 1]][j - 1]);
    		}
    	}
    	sort(e + 1, e + 1 + m, cmp);
    	for (int i = 1; i <= m; i++) {
    		LL tmp = 0;
    		if (flag[i])
    			tmp = ans;
    		else
    			tmp = ans - Maxpast(e[i].u, e[i].v) + e[i].w;
    		printf("%lld
    ", tmp);
    	}
    	return 0;
    }
    
  • 相关阅读:
    女子腰背疼痛案
    老人心悸心膝部无力屈伸不利案
    经方生姜泻心汤临床应用发挥
    电话求诊易误治
    女子乳房结块案
    小儿手足口案
    门纯德老先生经验
    男子肋部掣痛案
    加味潜降汤治疗阴虚阳亢之眩晕(来自网络)
    三叉神经痛与芎胡六虫汤
  • 原文地址:https://www.cnblogs.com/C202202chenkelin/p/15033423.html
Copyright © 2011-2022 走看看