并查集

畅通工程 (并查集)

浪子不回头ぞ 提交于 2019-11-28 20:16:30
Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? Input 测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 注意:两个城市之间可以有多条道路相通,也就是说 3 3 1 2 1 2 2 1 这种输入也是合法的 当N为0时,输入结束,该用例不被处理。 Output 对每个测试用例,在1行里输出最少还需要建设的道路数目。 Sample Input 4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0 Sample Output 1 0 2 998 #include <bits/stdc++.h> using namespace std; typedef long long ll; int a[1000+5],n,k,l,r; int find(int t) { return t == a[t] ? t : find(a[t]); ////缩点

算法笔记·并查集

筅森魡賤 提交于 2019-11-28 20:10:42
并查集 并查集我个人认为一种用来处理某些 特殊数据结构 的算法,其优点在于 程序简短 ,能够 快速简洁 的表达出点与点,数于数之间的关系。 这种算法有两个操作, 合并 与 查询 合并:能够 高时效 的将某一些符合题目要求的数据合并在一个 集合 中 查询:能够 高时效 的查询某个指定数据是否 存在于某个集合 之中,或者是计算满足题目要求的 集合数量 那么这个算法是如何运作的呢? 接下来我们看几道例题 例题1.亲戚 Luogu传送门 这是一道十分简单的并查集入门题,这里用来讲述并查集的运作思路。 根据题意,如果B是A的亲戚,C是B的亲戚,那么ABC三个人互为亲戚,也就是说ABC三个节点可以被放置在 同一个 集合当中,为了方便表述,我们可以认为这是一颗树,A是根,B是A的子节点,C是B的子节点。 由此,我们便可以利用并查集,将有亲戚关系的两个节点,进行 建边 ,即将两个有亲戚关系的节点 所处的集合进行合并 ,在查询时,只要利用一个 递归 ,不停向上询问,直到问到自己的 根节点 ,如根节点相同,便是有亲戚关系。 但是,还有一个问题,如此下来某个点都向上询问一遍,将会耗费大量的时间,那么何来高时效之说呢? 这里我们需要对并查集做一个 优化 ,使其能更快的计算出自己的根节点,我称之为 缩点 ,将所有有关系的点都进行直接 挂靠 ,也就是说,构造出一颗深度为2的树,如图。 如此一来

[Gym-102346A] 偷偷偷 并查集处理图(坐标)

旧城冷巷雨未停 提交于 2019-11-28 20:05:19
https://vjudge.net/problem/Gym-102346A 题意:判断监控器的范围能不能阻断左下角和右上角。 分析:利用并查集处理图,能连接起来的监控器合并起来,然后在最后标记每个集合能否连接到左下、右上、左右、上下的边界形成阻断。 注意: 每个集合可以用 find( x ) 到的祖先下标标记。 #include <bits/stdc++.h> using namespace std; const int maxn = 1e5+5; const int mod=998244353; int pre[maxn]; struct node{ int x,y,l; }s[maxn]; bool check(node a,node b){ return ( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) <= (a.l+b.l)*(a.l+b.l)); } int find(int x){ if(x!=pre[x]){ pre[x] = find(pre[x]); } return pre[x]; } void Union(int x,int y){ int rx=find(x),ry=find(y); if(find(x) != find(y)){ pre[rx] = ry; } } struct Node{ int x,y,a,b;

AcWing - 257 - 关押罪犯 = 并查集

两盒软妹~` 提交于 2019-11-28 19:43:37
https://www.acwing.com/problem/content/259/ 这道题蛮有趣的。 思路之一,是边带权并查集,相当于给点黑白染色,经过一条边权为1的边则改变一次颜色,规定到根节点边权和为0的为黑色。这样做的时候需要注意,合并两个不同并查集的x,y的时候,需要注意现在的黑白色只是当前连通块以内的颜色,当某次操作需要把两个不同连通块之间的黑色连在一起,则边权要带1,使子树的颜色全部翻转。 更简单的思路是,为每个人维护一个“对方集合”代表元素,每次把x,y合并的时候,假如x的“对方集合”为空则把y作为“对方集合”的第一个元素,否则把y和x的“对方集合”合并。假如某次要合并的x,y本身就在同一个集合中,直接false。 #include<bits/stdc++.h> using namespace std; typedef long long ll; int fa[20005]; bool d[20005]; int find(int x) { if(x == fa[x]) return x; int rt = find(fa[x]); d[x] ^= d[fa[x]]; return fa[x] = rt; } void merge(int x, int y) { int fx = find(x); int fy = find(y); if(d[x] == d[y]

并查集(不相交集合)详解与java实现

梦想的初衷 提交于 2019-11-28 19:31:38
目录 认识并查集 并查集解析 基本思想 如何查看a,b是否在一个集合? a,b合并,究竟是a的祖先合并在b的祖先上,还是b的祖先合并在a上? 其他路径压缩? 代码实现 结语 @(文章目录) 认识并查集 对于 并查集(不相交集合) ,很多人会感到很 陌生 , 没听过或者不是特别了解 。实际上并查集是一种挺高效的数据结构。 实现简单 ,只是所有元素统 一遵从一个规律 所以让办事情的效率高效起来。 对于定意义,百科上这么定义的: 并查集,在一些有N个元素的集合应用问题中,我们通常是在 开始时让每个元素构成一个单元素的集合 ,然后按一定顺序 将属于同一组的元素所在的集合合并 ,其间要 反复查找 一个元素在哪个集合中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。 并查集是一种 树型的数据结构 ,用于 处理一些不相交集合(Disjoint Sets)的合并及查询问题 。常常在使用中以 森林 来表示。 并查集解析 基本思想 初始化 ,一个森林每个都为独立。通常用数组表示,每个值初始为-1。 各自为根 join(a,b) 操作。a,b两个 集合 合并。注意这里的a,并不是a,b合并,而是a,b的集合合并

【题解】CF1157E:Minimum Array

只谈情不闲聊 提交于 2019-11-28 19:30:55
原题传送门 刚刚自己研究出了一个小技巧 对于每一个 a i a_i a i ​ ,找 n − a i n-a_i n − a i ​ 是否存在,不存在就找 n − a i + 1 , n − a i + 2 n-a_i+1,n-a_i+2 n − a i ​ + 1 , n − a i ​ + 2 …以此类推 想到用链表去实现一个查询的操作,但是一个一个找还是太慢,这让我想到了并查集 并查集的路径压缩的思路正好可以用在这里优化链表的查找 Code: # include <bits/stdc++.h> # define maxn 200010 using namespace std ; int n , a [ maxn ] , cnt [ maxn ] , nxt [ maxn ] ; inline int read ( ) { int s = 0 , w = 1 ; char c = getchar ( ) ; for ( ; ! isdigit ( c ) ; c = getchar ( ) ) if ( c == '-' ) w = - 1 ; for ( ; isdigit ( c ) ; c = getchar ( ) ) s = ( s << 1 ) + ( s << 3 ) + ( c ^ 48 ) ; return s * w ; } int get ( int x

第四周训练 | 并查集

删除回忆录丶 提交于 2019-11-28 17:58:56
A - How Many Tables #include<iostream> using namespace std; const int maxn = 1050; int set[maxn]; void init_set() { for(int i=0;i<=maxn;++i)set[i]=i; } int find_set(int x) { return x==set[x]?x:find_set(set[x]); } void union_set(int x,int y) { x=find_set(x); y=find_set(y); if(x!=y)set[x]=set[y]; } int main() { int t,n,m,x,y; cin>>t; while(t--) { cin>>n>>m; init_set(); for(int i=1;i<=m;++i) { cin>>x>>y; union_set(x,y); } int ans=0; for(int i=1;i<=n;++i) { if(set[i]==i)ans++; } cout<<ans<<endl; } return 0; } 优化版,降低了树高: #include<iostream> using namespace std; const int maxn = 1050; int set[maxn]

并查集的实现查询图中有多少个连通分支

◇◆丶佛笑我妖孽 提交于 2019-11-28 16:10:56
所谓并查集算法,涉及到两个操作,一是寻找到祖先节点(我们可以定义数组parent[i]=i满足时,i为祖先节点),而是合并连通分支 import java.util.HashMap; import java.util.HashSet; public class UnionSet { public static void main(String[] args) { } int []parent; int r=0; //寻找祖先节点 public int find(int n){ while(n!=parent[n]){ parent[n]=parent[parent[n]]; n=parent[n]; } return n; } //合并两个连通分支 public void union(int u,int v){ int pu=find(u); int pv=find(v); if(pu==pv){ return; } r++; parent[pu]=pv; } public int findCircleNum(int[][] M){ int n=M.length; parent=new int [n]; //初始化祖先节点 for(int i=0;i<n;i++){ parent[i]=i; } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){

poj1182食物链(三类并查集)

ぃ、小莉子 提交于 2019-11-28 16:05:11
动物王国中有三类动物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 AC代码: include include using

POJ 2492(权值向量并查集)

蹲街弑〆低调 提交于 2019-11-28 14:00:26
A Bug's Life Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 49835 Accepted: 16094 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs. Problem Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug