>传送门<

题意:最初有 n个人且互不认识,接下来 m行,每行有 x,y表示xy交朋友,朋友关系满足自反性和传递性,每次输出当前选取4个人且互不认识的方案数。

思路:比赛的时候知道是用并查集做,然而也只是知道,具体的思维还没有想到这一块,还是太菜了,得去多做多想~

并查集合并操作可以理解为使得两个集合的人互相成为朋友,也就是两个集合并在了一起,答案是要求从所有人中挑出四个互相不是朋友的四个人,比较基础的组合数学知识,但因为每个集合的大小预先不知,所以变得难以计算。

假设我们现在算出了合并前的答案,在合并xy时,设 num[x]x所在集合的集合大小,num[y] 同理。考虑这两个集合对答案的贡献,有三种情况:

  1. x所在集合中取一个人,然后再从其他非y集合中挑选出三个互不在同一集合的人
  2. y所在集合中取一个人,然后再从其他非x集合中挑选出三个互不在同一集合的人
  3. x,y所在集合中各取一个人,然后再从其他集合中挑选出两个互不在同一集合的人

考虑合并之后

可以发现合并之后xy在同一集合,仔细观察上面说到的情况1、2,它们对答案的贡献并没有因为合并操作而改变。只有情况3,在合并之后,该贡献被消灭,所以要用上一次的答案减去这个情况,就是合并之后的答案

那么该怎么计算呢?情况3的答案等同于x,y所在集合中各取一个人的情况总数)*(从其他集合中挑选出两个互不在同一集合的人的情况总数

这两个集合中各选一个人的情况是很好求的:num[x]*num[y]。

好,现在就只剩下求从其他集合中挑选出两个互不在同一集合的人的情况总数,这一看就有点不好求,不要紧,我们开动脑瓜子想一想。

现在我们有两种做法,一种是直接求,一种是间接的求。

我们先来看直接求的那一种

我们假设K从所有集合中挑选出两个互不在同一集合的人的情况总数,那么我们用K减去从所有集合中挑选出两个互不在同一集合的人(其中至少有一个来自x或y),那么相减的结果不就是从其他集合中挑选出两个互不在同一集合的人的情况总数么,对不对,仔细想想肯定是这样的

那答案就出来了,如果x,y不需要合并的话(即在同一集合内),答案自然也就不需要更新,直接输出上一次的答案即可,其余部分按并查集处理就OK了

 Code

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+; int n, m, x, y;
int f[maxn];
ll num[maxn];
ll K; //K表示从所有集合中挑选2个互不在同一集合的人的方案数
unsigned long long C; //C表示从所有集合中挑选4个互不在同一集合的人的方案数
int get(int x){
if (f[x]==x) return x;
return f[x]=get(f[x]);
}
void unite(int a,int b){
ll p = num[a]*num[b]; //从a, b所在集合中各取1个人的情况
ll q = num[a]*(n-num[a])+num[b]*(n-num[b])-num[a]*num[b]; //从所有集合挑选2个人(至少有一个来自a或b)的情况
ll k = K-q; //再从其他集合中挑选2个互不在同一集合的人
C -= p*k;
K = K-num[a]*num[b]; //由于a, b集合合并,K减去在同一集合中选2个人的方案
f[a] = b;
num[b] += num[a];
}
void init(){
C=1ull*n*(n-)/*(n-)/*(n-)/; //C初始化为从所有数中选4个的方案总数
K = 1ll*n*(n-)/; //K初始化从所有数中选2个的方案总数
for (int i = ; i <= n; i++) f[i] = i, num[i] = ;
}
int main()
{
scanf("%d%d", &n, &m);
init();
printf("%llu\n",C);
while(m--){
scanf("%d%d",&x,&y);
if (get(x)!=get(y))
unite(f[x],f[y]);
printf("%llu\n",C);
}
}

参考文章:
https://www.cnblogs.com/1625--H/p/11359772.html

2019牛客暑期多校训练营(第九场) E-All men are brothers(并查集+组合数学)的更多相关文章

  1. 2019牛客暑期多校训练营(第九场) D Knapsack Cryptosystem

    题目 题意: 给你n(最大36)个数,让你从这n个数里面找出来一些数,使这些数的和等于s(题目输入),用到的数输出1,没有用到的数输出0 例如:3  4 2 3 4 输出:0 0 1 题解: 认真想一 ...

  2. 2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵. 思路: 单调栈 全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如: 1 0 0 1 ...

  3. 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题)

    layout: post title: 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题) author: "luowentaoaa" c ...

  4. 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)

    题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9:  对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可.     后者mod=1e9,5才 ...

  5. [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem

    链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...

  6. 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...

  7. 2019牛客暑期多校训练营(第一场) B Integration (数学)

    链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...

  8. 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)

    链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...

  9. 2019牛客暑期多校训练营(第二场)F.Partition problem

    链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...

  10. 2019牛客暑期多校训练营(第八场)E.Explorer

    链接:https://ac.nowcoder.com/acm/contest/888/E来源:牛客网 Gromah and LZR have entered the fifth level. Unli ...

随机推荐

  1. Spring Cloud gateway 网关四 动态路由

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  2. 「刷题」GERALD07加强版

    是LCT了. 首先我们不知道联通块怎么数. 然后颓标签知道了是LCT. 那么考虑一下怎么LCT搞. 有一个很普遍的思路大家也应该都知道,就是如何求一个区间中某种颜色的个数. 这个可以很简单的用主席树来 ...

  3. Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring

    上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...

  4. JVM初体验

    一.设计堆内存溢出异常:OutOfMemoryError: public class Main { public static void main(String[] args) { List<D ...

  5. 1114作业 html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. python多进程总结

    概述 由于python中全局解释器锁(GIL)的存在,所以python多线程并不能有效利用CPU多核的性能(相当于单核并发)实现多线程多核并行,所以在对CPU密集型的程序时处理效率较低,反而对IO密集 ...

  7. mysql group by分组查询后 查询个数

    mysql group by分组查询后 查询个数2个方法随便你选 <pre>select count(distinct colA) from table1;</pre>< ...

  8. egret常用功能

    egret常用功能<pre>//////////////////////////////////////////////////////////////////////////////// ...

  9. day6-作业(不完整)

    # 1.用代码实现:利用下划线将列表的'每一个元素'拼接成字符串 li=['ndfj','dlfj',12434]# 注意是将元素与元素转换为字符串之间用_拼接,而不是将每个字符串进行拼接 li=[' ...

  10. 分组取topN

    假设有这样一个文件,文件内容如下 class1 class2 class1 class1 class2 class2 class1 class2 class1 class2 要求按照班级分组取出每个班 ...