链接: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.
输入
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.
题意:
每次给你一队朋友关系,问当前取四个人互相不是朋友的取法种类数,朋友关系有传递性
分析:
开始是,然后每一次并查集,判断(并修改),减掉不行的
显然就是当前要合并的两个朋友群各出一个,剩下的任出一个x,从不是x的朋友群里再抓一个;
kk是x可取的人数;sum记录的是截至上一个朋友关系,被合并的朋友群各选一个人的种类数总和;
所以有kk*kk-sum,还要再加上自己选自己,因为这样也是不合理的
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=1e5+7;
ull num[maxn];
int pre[maxn];
ull ans,n,sum;
int m;
int find(int x) {return pre[x]==x?x:pre[x]=find(pre[x]);}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
ull kk=n-num[fx]-num[fy];
ull tmp=num[fx]*num[fy]*(kk*kk-sum+num[fx]*num[fx]+num[fy]*num[fy])/2;
if(ans>tmp) ans-=tmp;
else ans=0;
sum+=2*num[fx]*num[fy];
pre[fy]=fx;num[fx]+=num[fy];num[fy]=0;
}
}
int main()
{
scanf("%llu%d",&n,&m);
for (int i=0;i<=(int)n;i++) pre[i]=i,num[i]=1;
ans=n*(n-1)/2*(n-2)/3*(n-3)/4;
sum=n;
while (m--)
{
printf("%llu\n",ans);
int u,v;scanf("%d%d",&u,&v);
if(ans==0) continue;
merge(u,v);
}
printf("%llu\n",ans);
return 0;
}