https://ac.nowcoder.com/acm/contest/889/E
这是题目链接,方便大家参考题意,大致意思就是给你n个人,m个关系变化就是让两个人交朋友,在每一次变化后求出还有独立四个人的方案数。思路我都写在代码注释里拉,大家可以参考一下:
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define max(a,b) a>b?a:b
using namespace std;
typedef long long ll;
typedef long double ld;
const int N=1e5+5;
int n,m;
ld ans,cnt;
int fa[N];
ld num[N];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
ld other=n-num[fx]-num[fy];
ans=ans-num[fx]*num[fy]*(cnt-num[fx]*num[fy]-num[fx]*other-num[fy]*other);//这个意思就是考虑每次减少的方案数。
//而减少的方案数一定就是从合并的两个集合各选出一个,然后再求出other里面选出两个的数量相乘,而other里面选出两个,求组合数肯定不行啦,那就得用原来的减去变少的。
//而原来的为cnt变少的有三个部分一是这两个集合中各选出一个,就是num[fx]*num[fy],还有就是other里面选出一个在其余两个集合在各自选一个,这样就好理解啦。
//ans=ans-num[fx]*num[fy]*(cnt-num[fx]*(n-num[fx])-num[fy]*(n-num[fy])+num[fx]*num[fy]);
cnt=cnt-num[fx]*num[fy];
fa[fx]=fy;
num[fy]+=num[fx];//这里面num存储的是子节点的数量。
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i,num[i]=1;
ans=(ld)n*(n-1)*(n-2)*(n-3)/24;
cnt=(ld)n*(n-1)/2;
printf("%.0Lf\n",ans);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
merge(u,v);
printf("%.0Lf\n",ans);
}
return 0;
}