传送门:https://ac.nowcoder.com/acm/contest/889/E
就记录一下每一块的人数,以及sum[1]表示所有人数,sum[2]表示所有团选2团的方案数,sum[3]表示选3团,sum[4]表示选4团。
每次合并x团和y团时,先从sum[1]减起,减到sum[4],吧x团和y团在sum[1..4]中的贡献全部减去
然后再从sum[4]加到sum[1],把x团和y团合并后的贡献全部加进去。
#include<bits/stdc++.h>
#define maxl 100010
using namespace std;
int n,m,top;
int f[maxl],tot,s[maxl];
__int128 t[maxl],one=1;
__int128 sum[5];
inline void prework()
{
tot=n;
for(int i=1;i<=n;i++)
f[i]=i,t[i]=one;
sum[1]=one*n;
sum[2]=one*n*(n-1)/2;
sum[3]=one*n*(n-1)*(n-2)/6;
sum[4]=one*n*(n-1)*(n-2)*(n-3)/24;
}
inline void print(__int128 x)
{
top=0;
if(x==0)
s[++top]=0;
while(x>0)
{
s[++top]=x%10;
x/=10;
}
for(int i=top;i>=1;i--)
printf("%d",s[i]);
puts("");
}
inline int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
inline void mainwork()
{
print(sum[4]);
int u,v,x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
x=find(u);y=find(v);
if(x!=y)
{
tot--;
if(tot>=4)
{
sum[1]-=t[x]+t[y];
sum[2]-=t[x]*sum[1]+t[y]*sum[1]+t[x]*t[y];
sum[3]-=t[x]*sum[2]+t[y]*sum[2]+t[x]*t[y]*sum[1];
sum[4]-=t[x]*sum[3]+t[y]*sum[3]+t[x]*t[y]*sum[2];
t[x]+=t[y];f[y]=x;
sum[4]+=t[x]*sum[3];
sum[3]+=t[x]*sum[2];
sum[2]+=t[x]*sum[1];
sum[1]+=t[x];
}
else
sum[4]=0;
}
print(sum[4]);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
}
return 0;
}