cf1108 F. MST Unification
题意:
给定无向带权图,每次操作选择一条边使其权加一,问至少几次操作后最小生成树唯一
思路:
法一:
首先随便用什么方法求出MST
对于某条不在MST中的边 \(e:u\stackrel{w}-v\),如果要把 \(e\) 加入MST中,就要删除 \(u\) 到 \(v\) 在MST上的路径(这路径当然是唯一的)上的随便一条边。
这个操作不能改变MST的边权和。 \(u\) 到 \(v\) 在MST上的路径上的最大边权为 \(W\),若 \(w<W\),加入 \(w\) 然后删除 \(W\) 就会使MST的边权和变小,若 \(w>W\) 则会变大,都是不合理的。所以只有一种情况 \(w=W\)
所以答案就是 边权等于两端点路径上的最大边权的边 的数量。用倍增求lca,同时记录 \(mx[x][k]\) 表示从节点 \(x\) 向根节点走 \(2^k\) 步经过的最大边权
int t, d[N], fa[N][20], mx[N][20];
void bfs() {
t = log2(n) + 1;
queue<int> q; q.push(1); d[1] = 1;
while(q.size()) {
int u = q.front(); q.pop();
for(auto [v,w]: G[u]) if(!d[v]) {
d[v] = d[u] + 1;
fa[v][0] = u, mx[v][0] = w;
for(int i = 1; i <= t; i++)
fa[v][i] = fa[fa[v][i-1]][i-1],
mx[v][i] = max(mx[v][i-1], mx[fa[v][i-1]][i-1]); //!!!
q.push(v);
}
}
}
int lca(int u, int v) {
int ans = 0;
if(d[u] > d[v]) swap(u, v);
for(int i = t; i >= 0; i--) if(d[fa[v][i]] >= d[u])
ans = max(ans, mx[v][i]), v = fa[v][i];
if(u == v) return ans;
for(int i = t; i >= 0; i--) if(fa[u][i] != fa[v][i])
ans = max({ans, mx[u][i], mx[v][i]}),
u = fa[u][i], v = fa[v][i];
return max({ans, mx[u][0], mx[v][0]}); //注意
}
void sol() {
cin >> n >> m; vector<edge> e(m);
for(auto &[u,v,w]: e) cin >> u >> v >> w;
vector<edge> oth; //不在MST中的边
iota(p, p + N, 0); //初始化并查集
sort(all(e));
for(auto &[u,v,w]: e)
if(get(u) != get(v)) mer(u,v), G[u].pb({v,w}), G[v].pb({u,w});
else oth.pb({u,v,w});
bfs(); //初始化倍增
int ans = 0; for(auto &[u,v,w]: oth)
ans += w == lca(u, v);
cout << ans;
}
法二:
考虑kruskal过程,\(S\) 表示所有权为 \(w\) 的边组成的集合。若 \(S\) 中的某条边的两端点在 \(S\) 之前已被连通,即已被某些边权 \(<w\) 的边连通,那么这条边就一点用都没有,不用考虑;否则,若某条边的两端点被 \(S\) 中的其他边连通,这条边就是冗余的,答案加一(实际操作时把它的权加一并弃用,因为后面也用不到)
void sol() {
cin >> n >> m; vector<edge> e(m);
for(auto &[u,v,w]: e) cin >> u >> v >> w;
sort(all(e));
iota(p, p + N, 0); //初始化并查集
int i = 0, ans = 0;
while(i < m) {
int j = i; while(e[i].w == e[j].w && j < m) j++; //e[i]~e[j-1]边权相同
for(int k = i; k < j; k++)
if(get(e[k].u) != get(e[k].v))
ans++;
for(int k = i; k < j; k++)
if(get(e[k].u) != get(e[k].v))
mer(e[k].u, e[k].v), ans--;
i = j;
}
cout << ans;
}

浙公网安备 33010602011771号