[All men are brothers](https://ac.nowcoder.com/acm/contest/889/E)
样例1:
6 6
1 2
3 4
4 5
3 5
3 6
2 4
输出:
15
9
4
0
0
0
0
样例2:
100000 0
输出
4166416671249975000
题意:
n个人,m个相互认识的关系,问从n个人中选择4个人,使其相互不认识的方案是多少;
分析:
最最暴力的方法就是每次都去查询n次,那么这样的复杂度是1e10,
因为每一次都去合并的话,答案是每次都是递减的,那么就看一下每次合并对答案的影响是多少,先看没有合并的时候,一共是有4种方案:
设需要合并的集合是t1与t2,那么剩下的集合用s来表示
- t1选1个,t2选1个,s选2个
- t1选1个,s选3个
- t2选1个,s选3个
- s选4个
然后再看合并之后的:
1.t1和t2中选1个,s选3个(这其实就是上面的2+3的方案数)
2.s选4个
这样看来就是只有第一种情况减少了,那么这样就可以减去第一种情况的方案数不就是答案了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<map>
#define rep(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
using namespace std;
const int N=1e5+10;
const int INF=0x3f3f3f3f;
ll c[N][6],ans4,ans2,sum[N];
int f[N];
int n,m;
int findf(int v){
if(v==f[v])
return v;
else
f[v]=findf(f[v]);
return f[v];
}
void merg(int x,int y){
int t1=findf(x),t2=findf(y);
if(t1!=t2){
f[t2]=t1;
ll s=n-sum[t1]-sum[t2];//不属于t1和t2的人数
ll t=ans2-s*sum[t1]-s*sum[t2]-sum[t1]*sum[t2];//从不属于t1和t2的人数选择两个人的方案数
ans4-=sum[t1]*sum[t2]*t;
ans2=t+s*(sum[t1]+sum[t2]);//合并之后的选择两个人的方案数
sum[t1]+=sum[t2];
sum[t2]=0;
if(ans4<0) ans4=0;
printf("%lld\n",ans4);
}else
printf("%lld\n",ans4);
}
void init(){
for(int i=1;i<=100000;i++) f[i]=i,sum[i]=1;
c[1][0]=c[1][1]=1;
for(int i=2;i<=n;i++){
c[i][0]=1;
for(int j=1;j<=4;j++)
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
scanf("%d%d",&n,&m);
init();
ans2=c[n][2];
printf("%lld\n",ans4=c[n][4]);
rep(i,1,m){int x,y;
scanf("%d%d",&x,&y);
merg(x,y);
}
return 0;
}