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

    题目大意:有一张$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
    ", ans);
    		else printf("%lld
    ", ans - ask(l[i], r[i]) + w[i]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    pl2303 驱动
    tomcat 启动脚本
    Linux下Shell命令加减乘除计算
    定时删除文件夹"$1"下最后修改时间大于当前时间"$2"天的文件
    mysql 拼接字符
    jquery iframe父子框架中的元素访问方法
    在线工具
    js对数组对象的操作以及方法的使用
    HTML 设置字体
    10月1号 备忘录
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9762235.html
Copyright © 2011-2022 走看看