并查集

第一天:树与并查集

眉间皱痕 提交于 2020-02-04 01:53:33
一、树   1、概念     根和深度     儿子父亲子树森林     叶子:没有儿子的节点     爸爸:父亲的父亲  2、 两点距离最短时过其公共祖先  3、任意两点之间加一条线变成一个环  4、直径:最远两点的路径     任取点P,搜索到P距离最远的Q,再搜索离Q最远的W,直径为QW(证明) 二、二叉树     1、 左右儿子,左右子树,    2、前序遍历:根,左子树,右子树      中序遍历:左,根,右    后序遍历:左,右,根       给两种求第三种     3、满二叉树 2^n-1个节点,最大深度为n      完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 三、并查集   路径压缩 测验 题目: 2003年4月16日,世界卫生组织根据包括中国内地和香港地区,加拿大、美国在内的11个国家和地区的13个实验室通力合作研究的结果,宣布重症急性呼吸综合征的病因是一种新型的冠状病毒,称为SARS冠状病毒。 很不幸,小明同学昨天晚上被确诊以经感染非典病毒,为此,校医院需要对他隔离治疗并隔离观察与他直接或间接接触者。 可以认为,同一个社团内如果有人感染病毒或可能感染病毒,那么这个社团内所有人都被认为是可能已经感染了病毒,由于时间紧迫

并查集——格子游戏

£可爱£侵袭症+ 提交于 2020-02-04 00:15:35
格子游戏 Alice和Bob玩了一个古老的游戏:首先画一个 n×n 的点阵(下图 n=3 )。 接着,他们两个轮流在相邻的点之间画上红边和蓝边: 直到围成一个封闭的圈(面积不必为 1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了,他们的游戏实在是太长了! 他们甚至在游戏中都不知道谁赢得了游戏。 于是请你写一个程序,帮助他们计算他们是否结束了游戏? 输入格式 输入数据第一行为两个整数 n 和 m。n表示点阵的大小,m 表示一共画了 m 条线。 以后 m 行,每行首先有两个数字 (x,y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是 D,则是向下连一条边,如果是 R 就是向右连一条边。 输入数据不会有重复的边且保证正确。 输出格式 输出一行:在第几步的时候结束。 假如 m 步之后也没有结束,则输出一行“draw”。 数据范围 1≤n≤200, 1≤m≤24000 输入样例: 3 5 1 1 D 1 1 R 1 2 D 2 1 R 2 2 D 输出样例: 4 比较水的一道题,开始hash来降维的时候没有保证唯一性WA了一发。 # include <bits/stdc++.h> using namespace std ; const int N = 3e4 + 7 ; int pre [ N ] , g [ 205 ] [ 205 ] ; int n , m ;

1034 Head of a Gang (仅得24分)

纵然是瞬间 提交于 2020-02-03 04:47:35
求连通分量 1.dfs 2.并查集 用并查集的时候,因为接下来可能还会更新通话分钟数u,我又不想把对应的一类存储再进行判断......所以就在合并时进行判断操作,寻找最大的点(pre) 实时更新 只需要确保更新完后后续的也一并压入即可。 4 5测试点没过 暂时不清楚哪里遇到问题了 #include<iostream> #include<cstdio> #include<map> #include<vector> #include<set> #include<algorithm> using namespace std; const int N = 4000+5; map<string, int> a; string Nm[N]; int Sum[N]; int Tot[N]; int pre[N]; struct Node { string Head; int Total, Num; Node() { Head=""; Total = 0; Num = 0; } }; int cmp(Node a, Node b) { return a.Head < b.Head; } map<int, Node> ans; int n, k, id = 1; vector<Node> V; bool flag[N]; set<string> S; void init() { for(int i

并查集——集合问题

不羁的心 提交于 2020-02-02 01:03:13
并查集——集合问题 题目描述 给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足: 若x在集合A中,则a-x必须也在集合A中。 若x在集合B中,则b-x必须也在集合B中。 输入描述: 第一行 三个数 n a b 1<=n<=1e5 1<=a,b<=1e9 第二行 n个数 p1 p2 p3…pn 1<=pi<=1e9 输出描述: 如果可以恰好分开就输出第一行 YES 然后第二行输出 n个数 分别代表pi 是哪个集合的 0 代表是A集合 1代表是B 集合 不行就输出NO 放在哪个集合都可以的时候优先放B 示例1 输入 4 5 9 2 3 4 5 输出 YES 0 0 1 1 示例2 输入 3 3 4 1 2 4 输出 NO # include <cstdio> # include <cstdlib> # include <cstring> # include <iostream> # include <algorithm> # include <map> using namespace std ; const int maxn = 1e5 + 50 ; int n , a , b , vis [ maxn ] , f [ maxn ] ; map < int , int > flag ; int find ( int x ) { if ( vis [ x ] ==

The Suspects(并查集入门)

别来无恙 提交于 2020-02-01 16:56:47
题目: http://www.fjutacm.com/Problem.jsp?pid=2021 题意大概就是输入n,m,分别代表总共n个人,m组,每组输入k,后面再输入k个人表示是一组的,0号是嫌疑者,输出和0在一组的人数(嫌疑者的人数)。 想看题目的点击这里哦:---> 题目 友情链接:---> 点我 咳咳,下面就是代码分析阶段,请看: #include<stdio.h> int fa[30005],n,rak[30005]; void chushihua()//初始化,把每个人的父节点先设为自己。rak就是代表的人数(同一个集合的人数) { for(int i=0;i<n;i++)//假设开始有n个集合 { fa[i]=i; rak[i]=1; } } int find(int x) { int r=x,temp; while(r!=fa[r]) r=fa[r]; while(x!=fa[x])//这里是路径压缩,让这棵树扁平化,把每个节点的父节点都直接变成根节点(让树变粗)。 { temp=fa[x]; fa[x]=r; x=temp; } return x; } void hebing(int a,int b)//合并操作,也有点小细节 { a=find(a); b=find(b); if(a!=b) { fa[b]=a; rak[a]+=rak[b];/

并查集

非 Y 不嫁゛ 提交于 2020-01-31 19:29:27
关于并查集的实现思路呢有两种,先讨论第一种 数组实现并查集 首先来看个案例 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 这是两串数字 但是,你们也可以当成索引,我自己连我自己,我的索引就是我自己,我对应的数也是我自己。 我们可以把这10个数的当成十个开发者,一开始我全能,我全栈,一个人接私活,我就是我,时间自由 但是这编号 7 的开发者他感觉一个人玩儿没劲,想有几个同事,想有几个伴儿,所以他去人才市场找了家公司, 这个编号 10 的开发者是个老板,这老板一看这 7 挺好啊,能吃能喝能拉能睡,就把他招入麾下,一个公司就有了俩开发者 这时候这十个人的关系就变化了。 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 10 8 9 10 这 7 他对应的就是10了。 这就产生了连接,10我是老板,7是他的下属员工。 来源: CSDN 作者: zxk_623797743 链接: https://blog.csdn.net/qq_19320773/article/details/104125717

并查集模板

人盡茶涼 提交于 2020-01-31 18:28:40
int par [ MAXN ] ; //父节点 int sum [ MAXN ] ; int Find ( int x ) { if ( par [ x ] != x ) par [ x ] = Find ( par [ x ] ) ; return par [ x ] ; } void Union ( int x , int y ) //合并x和y所在集合 { par [ Find ( x ) ] = Find ( y ) ; } int Abs ( int a ) { return a > 0 ? a : - a ; } void Merge ( int a , int b ) //合并a和b的集合(并查找集合个数) { int x = Find ( a ) ; int y = Find ( b ) ; if ( x != y ) { par [ y ] = x ; sum [ x ] + = sum [ y ] ; } } double Dis ( int a , int b ) { return sqrt ( double ( dx [ a ] - dx [ b ] ) * ( dx [ a ] - dx [ b ] ) + ( dy [ a ] - dy [ b ] ) * ( dy [ a ] - dy [ b ] ) ) ; } void init ( int n

寒假私训 ——并查集 B - 食物链

大兔子大兔子 提交于 2020-01-31 00:35:25
题目大意 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类。 第二种说法是"2 X Y",表示X吃Y。 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 1) 当前的话与前面的某些真的话冲突,就是假话; 2) 当前的话中X或Y比N大,就是假话; 3) 当前的话表示X吃X,就是假话。 你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 Input 第一行是两个整数N和K,以一个空格分隔。 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。 Output 只有一个整数,表示假话的数目。 Sample Input 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 Sample Output 3 解题思路 这一题容易想简单咯

并查集

三世轮回 提交于 2020-01-30 21:25:06
1.不相交集合操作: 集合嘛!就是集合论中的集合.它包括无序,确定,互异性. a.不相交集合定义:任意两个集合的交集为空.这样对于任意一个数据(元素),它只能属于这个不相交集合族中的某一个集合里面! b.其数据结构: 不相交集合数据结构保持一组不相交的动态集合S={S1, S2,…, Sk}。每个集合通过一个代表来识别,代表即集合中的某个成员。选择代表成员视乎具体应用,如选择最小元素。其中Si表示一个集合,Si这个集合可以通过其中的一个元素root予以代表. 2.对数据结构的操作:集合中的每一个元素是由一个对象表示的。设x表示一个对象,支持以下操作: 1)Make-set(x):建立一个新的集合,其唯一成员就是x。各集合是不相交的,所以x没有在其他集合中出现过; 2)Union(x,y):将包含x和y的动态集合(Sx和Sy)合并成一个新的集合(并集SxUSy),当然Sx和Sy是不相交的. 3)Find-set(x):返回一个指针,指向包含x的唯一集合的代表. 3.时间复杂度分析: 见算法导论! 分析要结合具体组织方式. 4.数据结构的组织方式: 一共有两种! 1.链表.即一条链表示一个集合 2.有根树.具体就是由一群树构成的森林 5.数据结构的优化: 可以采用以下两种方式进行优化: 1.路径压缩--两层深度的树,降低深度,方便find. 2.按秩合并--即考虑树结点数目

【luogu】p2024 食物链

你说的曾经没有我的故事 提交于 2020-01-30 18:36:51
题目链接w: https://www.luogu.com.cn/problem/P2024 是一个考察并查集的题,代码实现比较简单但思路真的很难想? 看了半天qbxt课件才看懂思路hmmm(菜 大概意思就是建立一个有三层的并查集 如果两个动物是同类就把它们放在同一层 如果x吃y就把y放在x上面的一层 也就是y+n和x在同一个集合 具体来说: (部分摘自课件) 对每个元素 x 建立 3个元素,xa,xb,xc。 其中xa = x,xb =x+n,xc =x+2*n 如果碰到“1 x y”,说明 x和y 是同类 如果 x 和 y + N 在一个集合里,ans++ 如果 x 和 y + 2 * N 在一个集合里,ans++ 合并 x 和 y, x + N 和 y + N,x + 2 * N 和 y + 2 * N 如果碰到“2 x y”,说明 x吃y 如果 x和y已经是同类,也就是x 和 y 在一个集合里,ans++ 如果 y吃x也就是x 和 y + 2 * N 在一个集合里,ans++ 合并x 和 y+N, x+N 和 y+2 * N,x+2 * N 和 y 补充 感觉上面解释的还是不太好懂,个人感觉根据样例手动把这个过程模拟一下会比较好理解hmmm luogu里第一篇题解写的超级详细可以去看hmm 如果还是不懂就看代码叭 #include<iostream> #include