Atcoder Beginner Contest 120D - Decayed Bridges 解题报告

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+ansi1

其中 s i z e size size u u u v v v 中的元素个数, a n s i − 1 ans_{i - 1} ansi1 为上一步答案。

如果不是,则说明不会对答案有贡献,此时答案为 a n s i − 1 ans_{i - 1} ansi1

最后逆序输出 n × ( n − 1 ) 2 − a n s i \frac{n\times(n-1)}{2}-ans_i 2n×(n1)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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值