Atcoder Beginner Contest 120D - Decayed Bridges 解题报告
1 题目链接
2 题目大意
题目:腐烂的桥梁
题目大意:
给定一张 n n n 个点, m m m 条边的无向图,现按输入顺序依次删除每一条边,求出每删除一条边是,有多少对 ( x x x, y y y) 不能联通,注意 ( x x x, y y y) 与 ( y y y, x x x) 为一种。
3 解法分析
这题要开long long
喔。
显然删边是没有学过的,只学过建边。
那不妨转换一下,变成建边,并查集维护即可。
用 s i z e size size数组维护连通块中元素的个数,连边后减去这两个联通块如果分开所产生的对数即可。
4 解法总结
刚开始时所有点都不连通, a n s ans ans 初值 0 0 0。
每加一条边,判断 u u u 与 v v v 是否属于同一个集合。
若在同一个集合,这一步的答案为: s i z e u × s i z e v + a n s i − 1 size_{u} \times size_{v} + ans_{i - 1} sizeu×sizev+ansi−1 。
其中 s i z e size size 为 u u u 与 v v v 中的元素个数, a n s i − 1 ans_{i - 1} ansi−1 为上一步答案。
如果不是,则说明不会对答案有贡献,此时答案为 a n s i − 1 ans_{i - 1} ansi−1。
最后逆序输出 n × ( n − 1 ) 2 − a n s i \frac{n\times(n-1)}{2}-ans_i 2n×(n−1)−ansi 即可。
5 AC Code
#include <bits/stdc++.h>
#define int long long
#define N 100007
using namespace std;
int n, m;
int ans[N];
int u[N], v[N];
int fa[N], cnt[N];
void init() {
for (int i = 1; i <= n; ++i)
cnt[i] = 1;
for (int i = 1; i <= n; ++i)
fa[i] = i;
}
int find(int x) {
return x != fa[x] ? fa[x] = find(fa[x]) : fa[x];
}
signed main() {
scanf("%lld%lld", &n, &m);
init();
for (int i = 1; i <= m; ++i)
scanf("%lld%lld", &u[i], &v[i]);
ans[m] = n * (n - 1) / 2;
for (int i = m; i > 1; --i) {
int x = find(u[i]), y = find(v[i]);
if (x == y)
ans[i - 1] = ans[i];
else {
ans[i - 1] = ans[i] - cnt[x] * cnt[y];
fa[y] = x;
cnt[x] += cnt[y];
cnt[y] = 0;
}
}
for (int i = 1; i <= m; ++i)
printf("%lld\n", ans[i]);
return 0;
}