题意:

给定一个点数为 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;
}

CF827D Best Edge Weight 题解的更多相关文章

  1. cf827D Best Edge Weight (kruskal+倍增lca+并查集)

    先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...

  2. CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]

    题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边. 这题还是要考察Kruskal的贪心过程. 先跑一棵MST出来.然后考虑每条边. 如果他是非树边,要让他Kruskal的时候被选入,必 ...

  3. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

  4. CF#633 D. Edge Weight Assignment

    D. Edge Weight Assignment 题意 给出一个n个节点的树,现在要为边赋权值,使得任意两个叶子节点之间的路径权值异或和为0,问最多,最少有多少个不同的权值. 题解 最大值: 两个叶 ...

  5. CF 633 div1 1338 B. Edge Weight Assignment 构造

    LINK:Edge Weight Assignment 这场当时没打 看到这个B题吓到我了 还好当时没打. 想了20min才知道怎么做 而且还不能证明. 首先考虑求最小. 可以发现 如果任意两个叶子节 ...

  6. 【Codeforces827D/CF827D】Best Edge Weight(最小生成树性质+倍增/树链剖分+线段树)

    题目 Codeforces827D 分析 倍增神题--(感谢T*C神犇给我讲qwq) 这道题需要考虑最小生成树的性质.首先随便求出一棵最小生成树,把树边和非树边分开处理. 首先,对于非树边\((u,v ...

  7. Codeforces 828F Best Edge Weight - 随机堆 - 树差分 - Kruskal - 倍增算法

    You are given a connected weighted graph with n vertices and m edges. The graph doesn't contain loop ...

  8. 浴谷夏令营例题Codeforces827DBest Edge Weight(三个愿望,一次满足~(大雾

    这题在浴谷夏令营wyx在讲的最小生成树的时候提到过,但并没有细讲怎么写... 这题可以用三种写法写,虽然只有两种能过...(倍增/倍增+并查集/树链剖分 先跑出最小生成树,分类讨论,在MST上的边,考 ...

  9. Codeforces827D. Best Edge Weight

    $n \leq 2e5,m \leq 2e5$的有边权图,对每条边问:不改其他边的情况下这条边最多能是多少使得他一定在所有最小生成树上,如果无穷大输出-1. 典型题+耗时题,CF上的绝望时刻..打VP ...

随机推荐

  1. 栈习题(1)-对于任意的无符号的的十进制数m,写出将其转换为十六进制整数的算法(正确输出即可)

    /*对于任意的无符号的的十进制数m,写出将其转换为十六进制整数的算法(正确输出即可)*/ /* 算法思想:利用辗转取余法,每次都将余数存入栈中,直到被除数等0,退出循环. 输出栈里的内容即可 */ v ...

  2. CSS中position和float的使用

    近期会更新一系列博客,对基础知识再度做个巩固和梳理. 一.position定位 (一):position的属性 1.absolute:生成绝对定位的元素,相对于最近一级定位不是static的父元素来进 ...

  3. 基于卷积神经网络的面部表情识别(Pytorch实现)----台大李宏毅机器学习作业3(HW3)

    一.项目说明 给定数据集train.csv,要求使用卷积神经网络CNN,根据每个样本的面部图片判断出其表情.在本项目中,表情共分7类,分别为:(0)生气,(1)厌恶,(2)恐惧,(3)高兴,(4)难过 ...

  4. python中的可哈希与不可哈希

    什么是可哈希(hashable)? 简要的说可哈希的数据类型,即不可变的数据结构(字符串str.元组tuple.对象集objects). 哈希有啥作用? 它是一个将大体量数据转化为很小数据的过程,甚至 ...

  5. 生物网络,RNA 与疾病关联分析

    题目: 大数据时代下基于网络算法和机器学习的非编码RNA 相关预测研究摘要:最近越来越多的生物实验表明非编码RNA 具有非常重要的生物学功能,参与细胞中的多项重要生命活动,调控许多基本且重要的生物过程 ...

  6. python-django框架中使用docker和elasticsearch配合实现搜索功能

    注意:系统环境为Ubuntu18 一.docker安装 0:如果之前有安装过docker使用以下命令卸载: sudo apt-get remove docker docker-engine docke ...

  7. python在linux中import cv2问题

    python中import cv2遇到的错误及安装方法标签 1 错误: ImportError: libXext.so.6: cannot open shared object file: No su ...

  8. windows下git创建本地分支并建立对应远程分支

    在对应项目目录下打开命令提示符 git branch -a      查看所有本地和远程分支 git checkout -b [newBranch]     建立本地分支newBranch git p ...

  9. python 操作excel实现替换特定内容

    本文介绍使用python语言,借助openyxl库来实现操作excel(xlsx)文件,实现替换特定内容的需求. 目前实现了3个小功能: 1. 全字匹配替换(mode1):(如:全字匹配 yocich ...

  10. WPF如何设置启动窗口

    在做系统时,我们想在启动时显示自己想显示的界面,和Winform不同的是它有两种方法 1.在App.xaml中 <Application x:Class="WpfApp1.App&qu ...