牛客第9场 All men are brothers(并查集)

本文探讨了一道关于朋友关系的组合计数问题,利用并查集算法进行高效求解。通过每次合并操作更新集合大小及组合数,计算在一系列操作后,从n个人中选择4个毫无关系的人的不同方式数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n个人,m个操作,每次操作可以把两个人和为朋友,朋友关系是相互的和传递的,问每次操作后,从这些人里挑出4个毫无关系的人的挑法有多少种。

思路:考虑每次合并减少了多少,减少的数目就是合并的两个集合的大小相乘再乘以剩下的不在一个集合的人中挑出两个人的数目。从不在一个集合里挑出两个人的挑法可以用任选两个的方案数减去在同一个集合挑两个人的挑法。

这道题当时想出了解法,但好久没写过并查集,忘了怎么在合并时顺便统计集合的大小,本身是签到题。

#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int N = 1e5 + 5;
ll f[N], u, v, sz[N], n, m;
ll F(ll x) {
    return f[x] == x ? x : f[x] = F(f[x]);
}
int main() {
    for(int i = 0; i < N; i++)
        f[i] = i, sz[i] = 1;
    cin >> n >> m;
    ll ans = n * (n - 1) / 2 * (n - 2) / 3 * (n - 3) / 4, s = 0;
    while(m--) {
        cout << ans << endl;
        cin >> u >> v;
        ll x = F(u), y = F(v);
        if(x == y)
            continue;
        f[x] = y;//y才是根节点!!!
        ll a = sz[x], b = sz[y];
        sz[y] += sz[x];//要用y!!!
        ll k = n - a - b;
        s -= (a * (a - 1) / 2 + b * (b - 1) / 2);
        ans -= a * b * (k * (k - 1) / 2 - s);
        s += (sz[y] * (sz[y] - 1)) / 2;
    }
    cout << ans << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值