zoukankan      html  css  js  c++  java
  • CF827D Best Edge Weight

    题意:

    给定一个点数为 n,边数为 m,权值不超过 (10^9) 的带权连通图,没有自环与重边。 现在要求对于每一条边求出,这条边的边权最大为多少时,它还能出现在所有可能的最小生成树上,如果对于任意边权都出现,则输出 (-1)

    这里写一个用倍增的(O(nlogn))做法。

    先求出一个最小生成树。

    1、若x到y在树上,那么对于任意一条非树边(e(a,b)),若满足a到b的树上路径经过(e(x,y))
    那么,根据最小生成树的性质,添加(e(a,b))后生成的环上的最大边必须是唯一的(e(a,b))
    因此,(e(x,y))的权值应当等于所有满足条件的(e(a,b))的最小权值减1。

    2、若x到y不在树上,那么,根据最小生成树的性质,添加(e(x,y))后生成的环上的最大边如果不是(e(x,y)),它就能出现。
    因此,(e(x,y))的权值应当等于x到y路径上的最大值减1。

    2可以使用倍增,(O(nlogn))

    对于1,我们可以把非树边从小到大排序,再依次做链上覆盖,保证每条树边只被其第一次覆盖。
    可以把被覆盖的连续边存成一个集合,用并查集维护。

    具体来说,并查集的根节点代表此点向上第一个未被覆盖的点(包括自身)。
    在这个点被覆盖后,把它与它的父节点的集合合并。

    每个点只会被考虑一次,所以复杂度是对的。
    总时间复杂度:(O(nlogn)),很好写。

    代码:

    #include <stdio.h> 
    #include <stdlib.h> 
    struct SBi {
    	int x,	y,	z;
    	SBi() {}
    	SBi(int X, int Y, int Z) {
    		x = X; y = Y; z = Z;
    	}
    };
    SBi bi[200010],px[200010];
    int cmp(const void * a, const void * b) {
    	return ((SBi * ) a) ->z - ((SBi * ) b) ->z;
    }
    int fu[200010],fr[200010],ne[400010],v[400010],w[400010],bs = 0;
    int getv(int x) {
    	if (fu[x] == x) return x;
    	fu[x] = getv(fu[x]);
    	return fu[x];
    }
    void addb(int a, int b, int c) {
    	v[bs] = b;
    	w[bs] = c;
    	ne[bs] = fr[a];
    	fr[a] = bs++;
    }
    void kru(int n, int m) {
    	for (int i = 1; i <= n; i++) {
    		fu[i] = i;
    		fr[i] = -1;
    	}
    	qsort(bi, m, sizeof(SBi), cmp);
    	for (int i = 0; i < m; i++) {
    		int x = getv(bi[i].x),y = getv(bi[i].y);
    		if (x == y) continue;
    		fu[x] = y;
    		addb(bi[i].x, bi[i].y, bi[i].z);
    		addb(bi[i].y, bi[i].x, bi[i].z);
    	}
    }
    int fa[200010],sd[200010],fb[200010],fg[200010];
    void dfs1(int u, int f) {
    	fa[u] = f;sd[u] = sd[f] + 1;
    	for (int i = fr[u]; i != -1; i = ne[i]) {
    		if (v[i] != f) {
    			fb[v[i]] = w[i];
    			dfs1(v[i], u);
    		}
    	}
    }
    int x[200010],y[200010],z[200010],bz[18][200010],zd[18][200010];
    void yucl(int n) {
    	for (int i = 1; i <= n; i++) {
    		bz[0][i] = fa[i];
    		zd[0][i] = fb[i];
    	}
    	for (int i = 1; i <= 17; i++) {
    		for (int x = 1; x <= n; x++) {
    			bz[i][x] = bz[i - 1][bz[i - 1][x]];
    			zd[i][x] = zd[i - 1][bz[i - 1][x]];
    			if (zd[i - 1][x] > zd[i][x]) zd[i][x] = zd[i - 1][x];
    		}
    	}
    }
    int getlca(int a, int b) {
    	if (sd[a] < sd[b]) {
    		int t = a;
    		a = b;b = t;
    	}
    	for (int i = 17; i >= 0; i--) {
    		if (sd[bz[i][a]] >= sd[b]) a = bz[i][a];
    	}
    	if (a == b) return a;
    	int rt;
    	for (int i = 17; i >= 0; i--) {
    		if (bz[i][a] == bz[i][b]) rt = bz[i][a];
    		else {
    			a = bz[i][a];
    			b = bz[i][b];
    		}
    	}
    	return rt;
    }
    int getmax(int a, int b) {
    	int lc = getlca(a, b),ma = -1;
    	for (int i = 17; i >= 0; i--) {
    		if (sd[bz[i][a]] >= sd[lc]) {
    			if (zd[i][a] > ma) ma = zd[i][a];
    			a = bz[i][a];
    		}
    	}
    	for (int i = 17; i >= 0; i--) {
    		if (sd[bz[i][b]] >= sd[lc]) {
    			if (zd[i][b] > ma) ma = zd[i][b];
    			b = bz[i][b];
    		}
    	}
    	return ma;
    }
    void fugai(int a, int b, int c) {
    	while (sd[a = getv(a)] > sd[b]) {
    		fg[a] = c;
    		fu[a] = getv(fa[a]);
    	}
    }
    int main() {
    	int n,m,k = 0;
    	scanf("%d%d", &n, &m);
    	for (int i = 0; i < m; i++) {
    		scanf("%d%d%d", &x[i], &y[i], &z[i]);
    		bi[i] = SBi(x[i], y[i], z[i]);
    	}
    	kru(n, m);dfs1(1, 0);yucl(n);
    	for (int i = 1; i <= n; i++) fu[i] = i;
    	for (int i = 0; i < m; i++) {
    		int a = x[i],b = y[i];
    		if (fa[a] != b && fa[b] != a) bi[k++] = SBi(a, b, z[i]);
    	}
    	qsort(bi, k, sizeof(SBi), cmp);
    	for (int i = 0; i < k; i++) {
    		int a = bi[i].x,b = bi[i].y,c = bi[i].z;
    		int lc = getlca(a, b);
    		fugai(a, lc, c);fugai(b, lc, c);
    	}
    	for (int i = 0; i < m; i++) {
    		int a = x[i],b = y[i];
    		if (fa[b] == a) {
    			a = y[i];
    			b = x[i];
    		}
    		if (fa[a] != b) printf("%d ", getmax(a, b) - 1);
    		else printf("%d ", fg[a] - 1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Javascript、C#、php、asp、python 等语言的链式操作的实现
    根据C# 事件思想来实现 php 事件
    initerrlog: 无法打开错误日志文件 'D:Program FilesMicrosoft SQL ServerMSSQL10_50.MSSQLSERVERMSSQLLog 解决办法
    64位直接加载个img 标签的src
    各种脚本语言变量作用域总结
    数据库设计14个技巧【转】
    基于Jquery 简单实用的弹出提示框
    C# dll 事件执行 js 回调函数
    php 配置xdebug
    sqlserver 构架与性能优化
  • 原文地址:https://www.cnblogs.com/lnzwz/p/11739748.html
Copyright © 2011-2022 走看看