All men are brothers

All men are brothers

牛客多校第九场E

给定n个人,起初互不认识

然后m各阶段

每个阶段有两个人x、y认识

求每个阶段选出四个人互不认识的方式

并查集

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll f[100004];
ll siz[100005];
///维护当前连通分支大小

ll n,m;
ll K;
ll tm=0;///所有连通分支大小的平方求和
void init()
{
    for(ll i=1;i<=n;i++){
        f[i]=i;
        siz[i]=1;
        tm++;
    }
}
ll cal(ll n)///算C (n,4)
{
   ll ans=(ll)(((n*(n-1))/2*(n-2))/3*(n-3))/4;
   return ans;
}
ll get(int x)
{
    return f[x]=(f[x]==x? x:get(f[x]));
}
ll uni(int x,int y)
{
    int a=get(x);
    int b=get(y);
    if(a==b)return 0;///连通分支个数不变,对答案不产生贡献
    ///两个连通分支合并
    ///产生的影响:原来答案中,可能选了一个属于a,一个属于b的情况,所以减去这部分情形
    ///即a中选一个,b中选一个,剩下的其他连通分支中选2个
    ///产生的贡献即为siz[a]*siz[b]*其他分支选两个
    ///其他分支计数,即(剩余的元素的个数的平方-其他分支的元素个数平方之和)/2
    tm-=(siz[a]*siz[a]+siz[b]*siz[b]);
    ll _=siz[a]*siz[b];
    siz[b]+=siz[a];
    ll o=n-siz[b];
    o=(o*o-tm)/2;
    _*=o;
    siz[a]=0;
    f[a]=b;
    K--;
    tm+=siz[b]*siz[b];
    return _;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    init();
    K=n;
    ll _y=cal(n);
    cout<<_y<<'\n';
    ll x,y,t;
    for(int i=0;i<m;i++){
        scanf("%lld%lld",&x,&y);
     
        if(K<4)cout<<0<<'\n';
        else{
           ll t= uni(x,y);
            _y-=t;
            cout<<_y<<'\n';
        }
    }

}

猜你喜欢

转载自www.cnblogs.com/liulex/p/11359678.html
ALL
今日推荐