链接:https://ac.nowcoder.com/acm/contest/889/E
来源:牛客网
题目描述
Amy asks Mr. B problem E. Please help Mr. B to solve the following problem.
There are n people, who don’t know each other at the beginning.
There are m turns. In each turn, 2 of them will make friends with each other.
The friend relation is mutual and transitive.
If A is a friend of B, then B is also a friend of A.
For example, if A is a friend of B, B is a friend of C, then A and C are friends.
At the beginning and after each turn, please calculate the number of ways to select four people from, such that any two of these four are not friends.
输入描述:
The first line contains two integers, n and m (n <= 100000, m <= 200000), which are the number of people, and the number of turns.
In the following m lines, the i-th line contains two integers x and y ( 1 <= x <= n, 1 <= y <= n, x ≠ y), which means the x-th person and the y-th person make friends in the i-th turn.
The x-th person and y-th person might make friends in several turns.
输出描述:
Output m+1 lines, each line contains an integer, which is the number of quadruples.
Output at the beginning and after each turn, so there are m+1 lines.
示例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
说明
Don’t use int.
题目大意:
先输入两个整数n,mn,mn,m,代表共有nnn个人,mmm次询问,最开始这nnn个人相互独立,每个人属于一个集合,需先输出从这nnn个人里选出444个人,要求选出的444个人人之间两两不在同一个集合中,问所有的情况数,对于mmm次询问,每次输入两个整数aaa,bbb,意思是将aaa所在的集合与bbb所在的集合合并,并输出这时选出的444个人人之间两两不在同一个集合的所有的情况数。
解题思路:
首先我们知道对于最开始的情况所有的方案数:ans=Cn4ans=C_n^4ans=Cn4,而后对于mmm次询问,我们先假设aaa所在的集合为AAA,bbb所在的集合为BBB,其他集合为CCC,如果需要将集合AAA与集合BBB合并,那么对于所有的情况数,相应的少了在AAA中选111人,在BBB中选111人,在CCC中选222人的情况,因此仅需在ansansans的基础上减去这些情况即可,即:ans=ans−CA1−CB1−CC2ans=ans-C_A^1-C_B^1-C_C^2ans=ans−CA1−CB1−CC2
而对于CA1C_A^1CA1与CB1C_B^1CB1我们仅需用并查集维护一下每个集合中的人数即可,而CC2C_C^2CC2则需另外维护,我们先假设num=Cn2num=C_n^2num=Cn2,而可知CC2=num−CA1∗CC1−CB1∗CC1−CA1∗CB1C_C^2=num-C_A^1*C_C^1-C_B^1*C_C^1-C_A^1*C_B^1CC2=num−CA1∗CC1−CB1∗CC1−CA1∗CB1,但还需记住每次合并后需将numnumnum更新回去,即num=num+CA+B1∗CC1num=num+C_{A+B}^1*C_C^1num=num+CA+B1∗CC1
代码:
//#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
ll jh[100100];
int f[100100];
ll C[100100][5];
void get_C() {C[0][0]=1;C[1][0]=C[1][1]=1;for(int i=1;i<=100000;i++) {C[i][0]=1;for(int j=1;j<=min(i,4);j++) {C[i][j]=C[i-1][j]+C[i-1][j-1];}}
}
int find(int x) {return x==f[x]?x:find(f[x]);
}
void merge(int a,int b) {int fa=find(a);int fb=find(b);if(fa!=fb) {if(fa<fb) {f[fb]=fa;jh[fa]+=jh[fb];jh[fb]=0;}else {f[fa]=fb;jh[fb]+=jh[fa];jh[fa]=0;}}
}
int main()
{#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);#endif//freopen("out.txt", "w", stdout);ios::sync_with_stdio(0),cin.tie(0);get_C();ll ans=1;ll n,m;ll num;cin>>n>>m;ans=C[n][4];if(n<4) {ans=0; }for(int i=1;i<=n;i++) {f[i]=i;jh[i]=1;}num=C[n][2];cout<<ans<<endl;ll a,b;for(int i=1;i<=m;i++) {cin>>a>>b;if(find(a)==find(b)) {cout<<ans<<endl;continue;}ll jha=jh[find(a)];ll jhb=jh[find(b)];num=num-(n-jha-jhb)*jha-(n-jha-jhb)*jhb-jha*jhb;if(num<0) num=0;merge(a,b);ans-=(jha*jhb*num);jha=jh[find(a)];num+=jha*(n-jha);if(ans<0) ans=0;cout<<ans<<endl;}return 0;
}