F. MST Unification
https://codeforces.com/contest/1108/problem/F
题意
n个点,m条边,每条边都有一个权值,每次操作可以使得一条边的权值减1,问最小需要几次操作,使得最小生成树唯一。
题解
对于最小生成树不唯一的情况就是,添加一条非树边后(u,v,w)后构成的环中的最小值(除非树边的最小值)等于非树边,这样就可以用非树边去替代这条边使得最小生成树不唯一,所以先构造一棵最小生成树,然后只需要对每条非树边(u,v,w)查询树边u到v中的最小值是否等于w,若等于则需要的操作+1。
这里查找树上(u,v)之间的最小值采用的是倍增LCA的方法。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 2e5+5;
int _max[maxn][20];
int dep[maxn];
struct Edge{
int v,c;
Edge(int _v,int _c):v(_v),c(_c){
}
};
vector<Edge> G[maxn];
int n,m;
void add(int f,int v,int c) {
G[f].push_back(Edge(v,c));
}
int p[maxn][20];
void dfs(int u,int fa) {
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i].v;
if(v == fa) continue;
_max[v][0] = G[u][i].c;
dep[v] = dep[u]+1;
p[v][0] = u;
dfs(v,u);
}
}
void initLCA() {
for(int i = 1; i <= 18; ++i)
for(int j = 1; j <= n; ++j) {
p[j][i] = p[p[j][i-1]][i-1];
_max[j][i] = max(_max[j][i-1],_max[p[j][i-1]][i-1]);
}
}
int LCA(int x,int y) {
if(dep[x] < dep[y])
swap(x,y);
int ans = 0;
for(int i = 18; i >= 0; --i)
if(dep[p[x][i]] >= dep[y]) {
ans = max(ans, _max[x][i]);
x = p[x][i];
}
if(x == y)
return ans;
for(int i = 18; i >= 0; --i) {
if(p[x][i] != p[