链接: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;
}