牛客多校第九场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'; } } }