题目链接:https://atcoder.jp/contests/abc120/tasks/abc120_d
题意 先给m条边,然后按顺序慢慢删掉边,求每一次删掉之后有多少对(i,j)不连通(我应该解释对了吧)
删边这个过程就可以从反方向进行,相当于从m到1慢慢加边
然后就把连通的用并查集存起来,另用一个s数组来存每个点和他连通的有几个点
不连通的就减去s[i]*s[j]就好了
初始的是C(n,2) 没边的时候所有点都不连通嘛。
代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; const int maxn = 1e5 + 10; pair<ll, ll> p[maxn]; ll par[maxn]; ll s[maxn]; ll sum; ll ans[maxn]; ll find(ll x) { return par[x] == x ? x : par[x] = find(par[x]); } int main() { ll n, m; scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) { par[i] = i; s[i] = 1; } for (int i = 0; i < m; i++) { scanf("%lld%lld", &p[i].first, &p[i].second); } sum = 1LL * n * (n - 1) / 2; for (int i = m - 1; i >= 0; i--) { ans[i] = sum; int x = find(p[i].first), y = find(p[i].second); if (x != y) { par[y] = x; sum -= s[x] * s[y]; s[x] += s[y]; } } for (int i = 0; i < m; i++) printf("%lld\n", ans[i]); return 0; }