2019牛客暑期多校训练营(第九场)E All men are brothers(并查集+组合数学)

链接:https://ac.nowcoder.com/acm/contest/889/E

题意:n个人,才开始互不认识。认识关系具有对称性和传递性。m个操作,每次选两个人,让他们互相认识。每次操作后,输出有多少种方式选4个人,这4个人互不认识。

思路:假设,现在选择的两个连通块分别有a、b个人。(用并查集维护。)考虑比上次答案减去了多少。原先选4个人时,其中两个人是这两个连通块中的人是合法的,现在不合法了。现在考虑,4个人中有两个人是这两个连通块中的人,有多少种选法。也就是从任选两个连通块中的人选法中(假设为pre2种),减去选一个a中的人(即a*(n-a)),再减去选一个b中的人(即b*(n-b)),再加上选a、b中的人(即a*b)(容斥原理)。减去的就是a*b*(pre2-a*(n-a)-n*(n-b)+a*b)。每次还要更新pre2的值,显然减去a*b即可。注意计算的过程中会超long long,long double 好了。

#include <bits/stdc++.h>
#define ll  long double
using namespace std;
const int N = 1e5+10;
ll ans,n,m,num[N],a,b,pre2;
int f[N];
void Init()
{
    for(int i=1;i<=n;i++)
        f[i]=i,num[i]=1;
}
int getf(int x)
{
    return f[x]==x?x:f[x]=getf(f[x]);
}
int main()
{
    int u,v,fu,fv;
    scanf("%Lf%Lf",&n,&m);
    Init();
    ans=n*(n-1)*(n-2)*(n-3)/24LL;
    pre2=n*(n-1)/2LL;
    printf("%.0Lf\n",ans);
    while(m--)
    {
        scanf("%d%d",&u,&v);
        fu=getf(u),fv=getf(v);
        if(fu==fv)
        {
            printf("%.0Lf\n",ans);
            continue;
        }
        a=num[fu],b=num[fv];
        ans=ans-a*b*(pre2-a*(n-a)-b*(n-b)+a*b); 
        pre2=pre2-a*b;
        f[fv]=fu;
        num[fu]+=num[fv];
        printf("%.0Lf\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值