并查集

洛谷 P1892 [BOI2003] 团伙 并查集&反集

匿名 (未验证) 提交于 2019-12-03 00:43:02
题目描述 1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是: 我朋友的朋友是我的朋友; 我敌人的敌人也是我的朋友。 两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。 输入输出格式 输入格式: 输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。 第二行M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。输入数据保证不会产生信息的矛盾。 输出格式: 输出文件gangs.out只有一行,表示最大可能的团伙数。 输入输出样例 复制 6 4 E 1 4 F 3 5 F 4 6 E 1 2 复制 3 看题目很容易想到用并查集来做,是朋友的直接合并就好了,那么敌人呢?,仔细读题,“我敌人的敌人也是我的朋友”这句话十分重要(有点熟悉怎么回事) 假设一共有1,2,3,4四个人,1和2是敌人,那么对与1和2,我们这样连 表示他们不在一个团伙中(不理解的话等下代码中会说) 最后统计所有f[i]==i的人数就是答案,为什么呢,因为每个人一定在团伙中,而每个团伙(即在并查集中)都有一个f[i]==i的祖宗,所以统计并输出即可

带偏移量的并查集

匿名 (未验证) 提交于 2019-12-03 00:40:02
// 带偏移量的并查集≈并查集补集 // 维护各点到父节点的距离 可用来分类 #include<iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; int n,f[ 1001 ],d[ 1001 ]; int find( int x) { if (x== f[x]) return x; d[x] += d[f[x]]; return f[x]= find(f[x]); } int get ( int x, int y) { int xx= find(x); int yy= find(y); if (xx!= yy) f[xx] = yy; } int main() { cin >> n; for ( int i= 1 ;i<=n;i++ ) f[i] = i; for ( int i= 1 ;i<=n;i++ ) { int u,v; cin >>u>> v; get (u,v); } return 0 ; } 原文:https://www.cnblogs.com/water-radish/p/9280539.html

How Many Tables//并查集

匿名 (未验证) 提交于 2019-12-03 00:34:01
题目: How Many Tables Problem Description Today is Ignatius‘ birthday. He invites a lot of friends. Now it‘s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius

并查集:按秩归并&amp;amp;路径压缩

匿名 (未验证) 提交于 2019-12-03 00:30:01
集合可以怎么表示?可以用一棵树来表示,结点表示集合的元素,而树根则用来代表这个集合。所以用树来做集合的并查集的话,对于查找某个元素属于哪个集合,我们就从这个结点开始往上找,找到它所在的这棵树的根结点。对于并集操作,只要把两棵树的根结点并在一起就可以了。所以为了满足这样的操作,我们的树结构有点小改变,变为 双亲表示法 “由孩子指向双亲。每个结点都向上指向它的父结点,而不是由父结点向下指向左右子树。”这样的树比较好的是用结构体数组来存储表示。 集合建立好后,接下来看查找操作: 38 for X i=0 i MaxSize S[ i ].Data!=X i++ i X X S[ i ].Parent>=0 S[ i ].Parent i S[ i ].Parent<0 return i 接着到集合的并运算。并运算是指给出两个元素的值,让你把这两个元素所在的集合并合在一起。这样操作我们要这样做: 1、首先要找到这两个元素所在的树的根结点(也就是找到这两个集合)。 2、判断这两个元素所在的集合是不是同一个集合,如果不是就做并运算,把其中一个树较矮的根结点指向另一个树较高的根结点的数组下标。 Parent 为什么要做这样一个查找操作?如果我们随便就把两棵树合并在一起,会出现怎样的一种情况?例如如果我们把一棵较高的树指向一棵较矮的树,那么合并后树的最大高度就会增加,随着并运算的操作次数越多

[HDU1232]畅通工程(并查集)

匿名 (未验证) 提交于 2019-12-03 00:29:01
给出城市的数量n以及道路的数量m,城市编号1~n,然后给出m个道路,输入 1 2 就是1、2之间修一条路,注意可以自身与自身连一条路。求还需要至少多少条路才能使道路畅通,即从任意一个城市出发可以到任何城市。 ˼· 第一次做并查集,看博客大体知道并查集的含义。所谓并查集其实是一种数据结构,一个集合,ADT分为 并 和 查 两个操作。首先我们开一个数组pre[], 根据名字可以知道pre[i] == j的含义是i的前一个数是j。这样我们可以根据任意一个结点找到他的根部,根据两个数的根是否相同判断这两个数是否在同一个集合之中。 让我们开始探索吧! int find( int x) { int r = x; while (pre[r] != r) //1.寻找路径的起点 r = pre[r]; int i = x, j; while (i != r) { //2.压缩路径 j = pre[i]; pre[i] = r; i = j; } return r; } 1.find函数的最主要的任务就是寻找路径的起点,所以用循环1来不断寻找前一个结点直到其前一个结点是自身为止。 2.压缩路径,其实这是一种优化,在本题中不压缩路径也可以过,因为数据少。压缩路径的好处是使所用结点直接指向根减少以后find时的循环1的次数。 void join( int x, int y) { int fx =

hdu3038(带权并查集)

匿名 (未验证) 提交于 2019-12-03 00:19:01
题目传送门 题目描述:给你n,m,n代表从1到n这么大的数组,m组v,u,val,代表v到u这个区间的总和是val,然后让你判断m组关系中有几组是错误的。 思路:带权并查集,这道题其实算是让我知道什么是真正的带权并查集吧,之前有一道食物链的题目非常经典但是一直没完全理解,其实带权并查集就是除了表达自己和父节点这个true的关系(fa[x])==y,意思就是,x->y true),还表达了自己和父节点的某一个权值关系。这个思想是看了大牛的博客 点击打开链接 其实带权并查集主要就是两个集合父节点的关系的更新,用了向量的思想,比如A的父节点是B,C的父节点是D,则A、B与父节点的权值表示为AB,CD,然后现在给你一组AC,也就是把AC两个节点放到一个集合里,那A、C的父节点B、D就也在一个集合里了,如果此时总爸爸是D,那B和D之间应该也有一个“BD”这样的关系,BD=BA+AC+CD=-AB+AC+CD.这就是向量。 而这道题u v区间要先表达成 u-1,v这样一个区间,比如告诉了你1-10的总和,现在判断1-4 和5-10 ,其实真正判断是(0,4】+(4,10】这样一个区间和是不是与【1,10】相等。 上代码咯 #include<iostream> #include<algorithm> #include<cstdlib> #include<sstream> #include

(带权并查集) HDU 3038 How Many Answers Are Wrong

匿名 (未验证) 提交于 2019-12-03 00:18:01
How ManyAnswers Are Wrong ProblemDescription TT and FF are ... friends. Uh... very verygood friends -________-b FF is a bad boy, he is always wooing TT to play the following game with him.This is a very humdrum game. To begin with, TT should write down a sequence ofintegers-_-!!(bored). Then, FF can choose a continuous subsequence from it(for example thesubsequence from the third to the fifth integer inclusively). After that, FFwill ask TT what the sum of the subsequence he chose is. The next, TT willanswer FF's question. Then, FF can redo this process. In the end, FF must workout the entire

【种类并查集】P2024 [NOI2001]食物链

匿名 (未验证) 提交于 2019-12-03 00:13:02
1 #include <iostream> 2 using namespace std ; 3 4 int fa [ 150010 ]; 5 int n , k ; 6 int cnt ; 7 8 int find ( int x ) 9 { 10 if ( x == fa [ x ]) return x ; 11 fa [ x ] = find ( fa [ x ]); 12 return fa [ x ]; 13 } 14 15 void merge1 ( int a , int b ) 16 { 17 fa [ find ( a )] = find ( b ); 18 fa [ find ( a + n )] = find ( b + n ); 19 fa [ find ( a + n * 2 )] = find ( b + n * 2 ); 20 } 21 22 void merge2 ( int a , int b ) 23 { 24 fa [ find ( a )] = find ( b + n + n ); 25 fa [ find ( a + n )] = find ( b ); 26 fa [ find ( a + n + n )] = find ( b + n ); 27 } 28 29 struct Edge 30 { 31 int u , v ; 32 }

区间 (模拟并查集优化)

匿名 (未验证) 提交于 2019-12-03 00:11:01
给出一个序列 a1, ..., an。 定义一个区间 [l,r] 是好的,当且仅当这个区间中存在一个 i,使得 ai 恰好等于 al, al+1, ..., ar-1, ar 的最大公因数。 求最长的好的区间的长度。 第一行 n,表示序列的长度; 第二行 n 个数 a1,a2,...,an。 输出一行一个数,表示最长的好的区间的长度。 题解写代码里可能容易懂? #include <cstdio> #define ll long long #define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout); using namespace std; inline ll read(){ ll x=0,f=1;char c=getchar(); while (c>'9'||c<'0') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } const int maxn(4e6+5); ll n,a[maxn],l[maxn],r[maxn],ans; void init(){ n=read(); for (int i(1);i<=n;++i) a[i]

十月末析题相关之并查集

倖福魔咒の 提交于 2019-12-03 00:08:39
对于第一次女生训练的析题相关: 首先是第一题: How Many Tables Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius