2019牛客暑期多校訓練營(第九場) E All men are brothers 並查集+數學

鏈接:https://ac.nowcoder.com/acm/contest/889/E?&headNav=acm&headNav=acm
來源:牛客網
 

題目描述

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個人,最初互不認識。有q組交朋友,每組x,y,表示xy交朋友。每一次,輸出從n個人中挑4個人,四個人互不認識有多少種可能。

思路:並查集維護朋友關係。假設上一次xy並不認識,而這一次xy認識了,那麼答案肯定會減少。減少多少呢?減少的是從x所在集合取一個人,從y所在集合取一個人,再從剩下的集合任選兩個集合從中挑兩個人。怎麼求呢?假設剩下集合大小爲a,b,c...。那麼從剩下的挑2個就有ab+ac+bc+...種可能,公式:ab+ac+bc+...=((a+b+c+.....)^2-(a*a+b*b+c*c+.....))/2;

假設sum1=a+b+c+....,sum2=a*a+b*b+c*c+.....。a,b合併後sum1不變,sum2=sum2-a*a-b*b+(a+b)^2=sum2+a*a*b;再維護一個sum2就行。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn=1e5+10;
int pre[maxn];
ll sum1,sum2,n,ans,num[maxn];
int find(int x)
{
	if(pre[x]!=x) pre[x]=find(pre[x]);
	return pre[x];
}
void merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx!=fy) pre[fx]=fy;
	if(fx==fy) return ;
	ans=ans-num[fx]*num[fy]*((sum1-num[fx]-num[fy])*(sum1-num[fx]-num[fy])-(sum2-num[fx]*num[fx]-num[fy]*num[fy]))/2;
	sum2+=2*num[fx]*num[fy];
	num[fy]+=num[fx];
	num[fx]=0;
}
int main()
{
	int m,x,y;
	scanf("%lld%d",&n,&m);
	sum1=sum2=n;
	for(int i=1;i<=n;i++) pre[i]=i,num[i]=1;
	ans=n*(n-1)/2*(n-2)/3*(n-3)/4;
	printf("%lld\n",n>=4?ans:0);
	while(m--)
	{
		scanf("%d%d",&x,&y);
		merge(x,y);
		printf("%lld\n",ans);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章