All men are brothers(并查集 数论)

**题目描述 **
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.

思路
并查集记录朋友状态,记录任选2个和任选4个的方案总数,每次更新朋友状态后更新,输出任选4个的方案总数

代码实现

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> P;
typedef long long ll;
const int N=100005;
const int INF=0x3f3f3f;
const ll mod=1e9;

int n,m,fa[N];
ll sum[N];
int vis[N];
ll C[N][5];

inline void init()
{
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        sum[i]=1;
    }
    for(int i=0;i<=n;i++) C[i][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i&&j<=4;j++)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
}

inline int Find(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=Find(fa[x]);
}

inline void Merge(int x,int y)
{
    fa[Find(y)]=Find(x);
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    ll ans4=C[n][4];
    ll ans2=C[n][2];
    printf("%lld\n",ans4);
    int t=n;
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(Find(a)==Find(b))
        {
            printf("%lld\n",ans4);
            continue;
        }
        int u=Find(a),v=Find(b);
        ans4-=(ans2-sum[u]*sum[v]-(sum[u]+sum[v])*(n-sum[u]-sum[v]))*sum[u]*sum[v];
        ans2-=sum[v]*sum[u];
        sum[u]+=sum[v];
        Merge(a,b);
        printf("%lld\n",ans4);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值