并查集

并查集

邮差的信 提交于 2020-01-29 01:43:16
1、并查集是什么 并查集是用来在一个集合中进行元素搜索,或者将集合合并的一种方法。主要通过数组来实现。 2、并查集的实现思路 我们可以将一个数组中每个单位存储的元素初始化为它的下标,代表初始时它的编号就是它自己。在之后的操作中,如果两个集合合并,那么就将其中一个集合编号所在的数组位置修改为另一个集合编号作为代表。这时,当我们搜索到这两个集合时,会发现它们的编号相同,即属于同一个集合。 3、代码实现 并查集主要有以下的几个操作 初始化 for ( int i = 0 ; i < n ; i ++ ) //n为集合编号的最大值 num [ i ] = i ; 查询操作 int find ( int x ) { int head = x ; while ( num [ head ] != head ) //查询所有集合中最终的编号 head = num [ head ] ; while ( x != num [ x ] ) //路径压缩,缩短下次搜索的时间 { x = num [ x ] ; num [ x ] = head ; } return head ; } 合并操作 void join ( int a , int b ) //将两个集合合并 { int a1 = find ( a ) ; int b1 = find ( b ) ; num [ a1 ] = b1 ; while

并查集扩展

梦想与她 提交于 2020-01-26 22:25:50
简单并查集。要注意的是,像这种结点带有很多信息,要求对结点信息按连通分量进行汇总的并查集,可以不要在union操作里进行,而选择在进行完所有合并后,对所有结点遍历进行汇总。这样不容易出错。 # include <stdio.h> # include <iostream> # include <algorithm> using namespace std ; # define MAX 10000 ///最大范围 int f [ MAX ] , vis [ MAX ] = { 0 } ; ///f用于记录并查集每个点的父亲 vis记录是否访问过 struct family ///家族结构体 { int id , people ; double area , house ; //area是占地面积 house是房产套数 } ; family person [ MAX ] , * ans [ MAX ] ; //person记录相应id的家族信息,ans是个指针数组,记录答案 int ant = 0 ; //ans数组下标 bool cmp ( family * a , family * b ) ///排序比较函数 { if ( ( a -> area / a -> people ) == ( b -> area / b -> people ) ) return a -> id < b -

基本算法学习笔记

爱⌒轻易说出口 提交于 2020-01-26 21:34:56
一、并查集(实质是有多棵树的森林) 优化: 路径压缩: 加快查找速度. 按秩合并: 使具有较少结点的树的根指向具有较多结点的树的根。 并查集删除点: 一开始就用虚拟根表示父节点。 要想直接通过修改father[x]来删除点,就必须一开始就用虚拟根表示父节点 HDU - 2473 https://blog.csdn.net/S_999999/article/details/82014819 带权并查集 (种类并查集 ): HDU 3038 https://blog.csdn.net/S_999999/article/details/95166617 POJ 1182 https://blog.csdn.net/S_999999/article/details/81148593 POJ 2492 https://blog.csdn.net/S_999999/article/details/95077786 POJ 1703 https://blog.csdn.net/S_999999/article/details/95169725 模板:HDU 1232 #include <iostream> using namespace std; int parent[1009],deep[1009]; void init(int n) { for(int i=1;i<=n;i++){

并查集:连通块中点的数量

半腔热情 提交于 2020-01-26 21:21:50
题目链接:https://www.acwing.com/problem/content/839/ 题意 :给定一个包含n个点(编号为1~n)的无向图,初始时图中没有边。 现在要进行m个操作,操作共有三种: 1,“C a b”,在点a和点b之间连一条边,a和b可能相等; 2,“Q1 a b”,询问点a和点b是否在同一个连通块中,a和b可能相等; 3,“Q2 a”,询问点a所在连通块中点的数量; 数据范围 1≤n,m≤105 输入样例: 5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5 输出样例: Yes 2 3 思路 :其实这个题和上一篇博客的题大同小异,只不过多了一个求节点数的过程,只要满足根节点的size[]有意义就可以了。 代码实现: # include <iostream> using namespace std ; const int N = 1e5 + 5 ; int n , m ; int p [ N ] , size [ N ] ; //返回x的根节点 + 路径压缩 int find ( int x ) { if ( p [ x ] != x ) p [ x ] = find ( p [ x ] ) ; return p [ x ] ; } int main ( ) { cin >> n >> m ; for ( int i = 1 ; i <= n

并查集:合并集合

梦想的初衷 提交于 2020-01-26 20:39:54
题目链接:https://www.acwing.com/problem/content/838/ 题意 :一共有n个数,编号是1~n,最开始每个数各自在一个集合中。 现在要进行m个操作,操作共有两种: 1,“M a b”,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作; 2,“Q a b”,询问编号为a和b的两个数是否在同一个集合中; 数据范围 1≤n,m≤1e5 输入样例: 4 5 M 1 2 M 3 4 Q 1 2 Q 1 3 Q 3 4 输出样例: Yes No Yes 思路 并查集有两个高效 运用 :1,将两个集合合并 2,询问两个元素是否在同一个集合种。 并查集的 原理 :每个集合用一棵树来表示,树根的编号就是整个集合的编号,每个节点储存它的父节点,p[x]表示x的父节点。 相关 处理 :1,如何判断树根:if(p[x] == x) 2,如何求x的集合编号:while(p[x] != x) x = p[x]; 3,如何合并两个集合:px是集合x的编号,py是集合y的编号,p[x] = y。 代码实现: # include <iostream> using namespace std ; const int N = 1e5 + 5 ; int n , m ; int p [ N ] ; //返回x的根节点 + 路径压缩 int find

并查集

岁酱吖の 提交于 2020-01-26 18:17:19
一、概念 一个集合中的元素,仅有的关系就是同属于这个集合,并查集就是用来维护若干集合的一种数据结构。 并查集有两个基本操作: 并:合并两集合; 查:查询两个元素是否属于同一个集合。 为了方便地实现合并以及查找操作,我们在一个集合中规定唯一一个根结点,并将这个根结点作为该集合的标志。 开始时所有元素都是一个独立的集合: int parent[MAXN]; for(int i = 0;i < n;i++) { parent[i] = i; //i元素的父结点初始化为自己,也可以初始化为-1 } 二、合并与查找 Find 查找的同时可以通过 路径压缩 来将均摊复杂度降低为 \(O(1)\) 。查找某个结点时,将其经过的全部直接连到父结点,这样下次查询时次数就会减少。 Union 合并时可以遵循 按秩合并 原则,将秩小的树合并到秩大的树,降低路径压缩时的开销。 将两个不同的集合合并为一个集合,只要将其中一个集合的根结点的 parent 指向另一个集合的根结点即可。 对于属于同一个集合的两个元素的合并没有意义,所以我们一般只对两个不同的集合进行合并。 class unionFind { private: vector<int> parents_; vector<int> ranks_; public: unionFind(int n) { ranks_ = vector<int>(n, 0)

POJ 1182食物链(带权并查集)

妖精的绣舞 提交于 2020-01-26 14:53:34
传送门 Description 动物王国中有三类动物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 首先对于这道题

# [acwing 240] 食物链 [并查集]

风格不统一 提交于 2020-01-26 13:33:49
[acwing 240] 食物链 [并查集] 传送门 题意 ABC三种动物,食物链构成一个环形,,给出M个关于彼此关系的描述,判断有多少个假话。 1 X Y表示同类 2 X Y表示X吃Y 思路 本题是并查集的一种比较新颖的用法,并查集一般用来维护集合,但是在这里主要是使用路径压缩来维护点和根之间的距离。 动物之间有三种关系(同类,捕食,被捕食),并且食物链构成环,那么可以使用和根之间的距离模3来区分三种关系,这里并不严格划分集合,主要是借助了并查集中的路径压缩。 红色的线是不存在的,只是为了方便理解。图中的关系是: 2吃1 ,3吃2,4吃3,6吃4,5吃1。 其中3被1和4吃,那么1和4是同类(因为食物链是环形的,吃同一种动物的就是同类),1和4到1的距离模3都是0。 2,5,6是同类,模3都是1,都是1的捕食者 使用d[]维护节点x到父节点的距离,路径压缩时只要更新d[]的值 Code: #include <iostream> using namespace std; const int maxn=5e4+10; int n,m; int p[maxn],d[maxn]; inline int find(int x){ if(p[x]==x)return x; int t=find(p[x]); d[x]+=d[p[x]];//x节点到父节点p[x

P3402 【模板】可持久化并查集(可持久化并查集模板)

喜夏-厌秋 提交于 2020-01-25 14:00:49
题目链接: 模板题 普通的并查集是通过 f a fa f a 数组来实现的(或者说是 p p p 数组) 可持久化并查集,就是用主席树来维护并查集的 f a fa f a 数组(因为主席树可以记录过去的版本),使之能回退到过去的版本,这里的版本指的是某个操作之前的 f a fa f a 数组 可持久化并查集的合并部分使用的不是路径压缩来优化,而是使用启发式合并:两棵树合并时,将树深小的合并到树深大的,这样树的高度增长比较慢。 若合并两棵树,新的树的高度会增长,那么树的 s i z e size s i z e 至少扩大两倍,因此树高至多增长 log ⁡ n \log n lo g n 次,每次增长的值为 1。 主席树部分: 先建一棵初始的主席树,令每个下标 i i i 的 f a [ i ] = i fa[i] = i f a [ i ] = i void build ( int & rt , int l , int r ) { rt = ++ sz ; if ( l == r ) { dep [ rt ] = 1 ; fa [ rt ] = l ; return ; } int mid = l + r >> 1 ; build ( lson [ rt ] , l , mid ) ; build ( rson [ rt ] , mid + 1 , r ) ; } 更新

从文件夹的角度解读算法——并查集

你说的曾经没有我的故事 提交于 2020-01-23 22:48:25
文件与并查集 1、并查集概念 2、文件与并查集的联系 (1)组合模式 (2)文件夹查询 (3)文件夹合并 3、并查集算法源码 (1)初始化 (2)查询 (3)合并 (4)路径压缩 (5)测试 1、并查集概念 根据百度百科的权威解释,并查集的定义大概如下所示: 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。 这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 2、文件与并查集的联系 (1)组合模式 说到树形结构,计算机里有一样众人皆知的东西——文件,其实就可以用树形结构来表示。 如果你上过设计模式这门课,GOF常用的23种设计模式中 结构型模式类别 中的 组合模式 ,其中有一个经典的例子讲的就是文件。 那什么是组合模式呢,我们先来看看它的定义: 组合模式,将对象组合成树形结构以表示“部分-整体