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