并查集

noip模拟【20171103】

孤人 提交于 2019-11-27 08:15:55
T1 [dp] 以时间为关键字先排序。 F[i]表示到t[i]时刻,并且尽量拦截对应的子弹,最多可以拦到几发子弹,在自身没有死掉的情况下。如果向后转移时,前面多个点可以拦截的子弹数目都相同,那么选择时间最靠后的一个。 注意有些子弹根本无法拦截,所以初值赋值为极小值。 If(D(i,j) <= t[j]-t[i] /*可以选择*/|| (m1 – (t[i]-f[i])*d) < 0/*必须选择*/)f[i] = max(f[i],f[j] + 1); 并且在中途不会死亡的情况下,尽量靠后选择,取max。 T2 [数学,二分] 对于每个x[i],x0取到x[i]的时候单个贡献取到最小值,非x[i]时成单增或单减,其函数图像类似于二次函数y = a*x^2。其导函数为单增,易知对于每个x[i]来讲,x0在实数范围都是单增的。那么我们可以对于x0进行二分,每个导函数进行相加比较,求出取到贡献最小的x0。 T3 [并查集] 将一样强的炮台放入一个并查集中,如果有炮台比并查集中的炮台强,则并查集中的炮台全部不可行。并查集扫完之后再判断可行炮台的数量。 来源: https://www.cnblogs.com/ve-2021/p/11353928.html

并查集 带权并查集

筅森魡賤 提交于 2019-11-27 08:07:06
描述 小Hi的学校总共有N名学生,编号1-N。学校刚刚进行了一场全校的古诗文水平测验。 学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分。 小Hi想知道利用这些消息,能不能判断出某两位同学之间的分数高低? 输入 第一行包含三个整数N, M和Q。N表示学生总数,M表示小Hi知道消息的总数,Q表示小Hi想询问的数量。 以下M行每行三个整数,X, Y和S。表示X号同学的分数比Y号同学的分数高S分。 以下Q行每行两个整数,X和Y。表示小Hi想知道X号同学的分数比Y号同学的分数高几分。 对于50%的数据,1 <= N, M, Q <= 1000 对于100%的数据,1 <= N, M, Q<= 100000 1 <= X, Y <= N -1000 <= S <= 1000 数据保证没有矛盾。 输出 对于每个询问,如果不能判断出X比Y高几分输出-1。否则输出X比Y高的分数。 样例输入 10 5 3 1 2 10 2 3 10 4 5 -10 5 6 -10 2 5 10 1 10 1 5 3 5 样例输出 -1 20 0 本题目是一个带权并查集问题,tcl,一开始想成了最短路,对于本题而言,带权并查集的权值是当前点和根节点的差值,更改权值的操作应该是在合并的时候,因为合并时根节点会相应的发生变化,首先是将一个根并到另一个根上

用并查集合并不同的集合

自作多情 提交于 2019-11-27 06:42:21
Description 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。 Input 第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。 以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有亲戚关系。 接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。 Output P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。 Sample Input 6 5 3 1 2 1 5 3 4 5 2 1 3 1 4 2 3 5 6 Sample Output Yes Yes No View Code #include<iostream> using namespace std; #define size 5001 int father[size]; int find( int k) { return father[k]==k?k:father[k]= find(father[k]); } int main() { int n, m, p,

P3367 【模板】并查集

怎甘沉沦 提交于 2019-11-27 06:08:24
P3367 【模板】并查集 题目描述 如题,现在有一个并查集,你需要完成合并和查询操作。 输入格式 第一行包含两个整数N、M,表示共有N个元素和M个操作。 接下来M行,每行包含三个整数Zi、Xi、Yi 当Zi=1时,将Xi与Yi所在的集合合并 当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N 输出格式 如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N 输入输出样例 输入 #1 复制 4 7 2 1 2 1 1 2 2 1 2 1 3 4 2 1 4 1 2 3 2 1 4 输出 #1 复制 N Y N Y 说明/提示 时空限制:1000ms,128M 数据规模: 对于30%的数据,N<=10,M<=20; 对于70%的数据,N<=100,M<=1000; 对于100%的数据,N<=10000,M<=200000。 忽然发现我真的是太蒟了 连并查集都不会 今天自学了一波(不过是简单并查集) 代码如下(根据感觉瞎敲了一顿,居然A了) #include<bits/stdc++.h> #define maxn 10005 using namespace std; int fa[maxn]; int find(int x) { if(fa[x]==x) return x; fa[x]=find(fa[x]); return fa[x];

可持久化并查集、可撤销并查集

牧云@^-^@ 提交于 2019-11-27 05:18:22
主要学习的 blog / 整理下可持久化并查集要完成的内容: 1、将一个点的父节点进行更改 (实际上是新增一个信息点)update。 2、查找某个时间点下一个pos对应的信息点编号。 3、查找一个点的父节点。 4、更新一个点的deep值,不用新写函数,可以用3号操作找到编号后++。 5、初始化build。 // #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> #include <unordered_map> // #include<bits

AcWing 240. 食物链 | 并查集

本小妞迷上赌 提交于 2019-11-27 05:10: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和K句话,输出假话的总数。 输入格式 第一行是两个整数N和K,以一个空格分隔。 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。 输出格式 只有一个整数,表示假话的数目。 数据范围 1 ≤ N ≤ 50000 1≤N≤50000, 0 ≤ K ≤ 100000 0≤K≤100000 输入样例: 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 输出样例: 3 题解: 这题我们有两种解法

集训队8月12日(并查集)

只谈情不闲聊 提交于 2019-11-27 04:44:24
刷题数:8 今天看了并查集,算法竞赛指南192~202页。 写了五篇博客。感觉对并查集的概念以及用法加深了许多。 并查集+离散化 https://www.cnblogs.com/2462478392Lee/p/11338117.html 并查集+贪心 https://www.cnblogs.com/2462478392Lee/p/11338340.html 并查集变形 https://www.cnblogs.com/2462478392Lee/p/11343655.html 并查集+扩展域+离散化 https://www.cnblogs.com/2462478392Lee/p/11343747.html 并查集+扩展域(经典) https://www.cnblogs.com/2462478392Lee/p/11343788.html 总结 感觉今天还算充实,以后加油!! 来源: https://www.cnblogs.com/2462478392Lee/p/11343822.html

食物链(并查集经典题)

倾然丶 夕夏残阳落幕 提交于 2019-11-27 04:43:26
思路:写了这题 https://www.cnblogs.com/2462478392Lee/p/11343747.html 就很容易理解,并想出思路了。开一个3*n的数组,将x与y的同类,捕食者,和被捕食做扩展域, 然后利用其中的关系做并查集,每一种情况均有三种。当x与y为同类时,同类同类,x的捕食者与y的捕食者,x的被捕食与y的被捕食。当x捕食y时,x与y的捕食者,x的被捕食 与y,x的捕食者与y的被捕食。建立并查集后查看多少种不符合当前并查集情况即可求出答案。 #include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #include<cstdio> #include<cmath> #define ll long long using namespace std; int fa[2000000]; int get(int k) { return fa[k]==k?k:fa[k]=get(fa[k]); } void merge(int x,int y) { fa[get(x)]=get(y); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=3*n;i++) { fa[i]=i; } int

图论神仙题大赏

妖精的绣舞 提交于 2019-11-27 04:04:25
BZOJ 3445 Roadblock 先跑一边最短路,然后枚举最短路上的每条边,将路径翻倍然后跑Dijstra. 因为不在最短路径上的边没用贡献,然后最短路径最长为 n−1 复杂度 O(nmlogm) BZOJ 1579 道路升级 两维:k使用了多少次更新,u最短路ww咱可以跑dp? 分层图,第一层:原图,第二层内部:原图,然后从第一层点u向第二层点v连一条长度为0的边,从第二层点v再向第一层点u连一条长度为0的边。 因为有可能用不完k个,所以需要从u到u连一条长度为0的边(单向的) BZOJ 4152 The Captain 假设 \(x_1<x_2<x_3\) 那么选择 \(x_3\) 不如选择 \(x_1->x_2\) ,再选择 \(x_2\) 到 \(x_3\) 按x轴排序,相邻的点建边,然后就是O(n); 按照某维坐标排序,相邻两个点在这一维度上的差值最小,所以两两连边,长度为这一维度上的差值(不用考虑另外一维度的,就算另外一维度的更小,在连另外一维度的时候也能够抵达)。然后跑最短路即可。 BZOJ 1050 旅行 COMF 枚举最小边,然后大概就是跑最小生成树的思路,然后找最大边 枚举最小边,用更大的边做 Kruskal,当 S 和 T 连通立即 Break。 LCT,从大到小加边维护最小生成树。 1.边按权值排序,标号1~m 2.初始化一个枚举起点sta=1 3

并查集

☆樱花仙子☆ 提交于 2019-11-27 03:37:44
并查集的算法应用 欧拉回路中判断图是否联通 最小生成树克鲁斯卡算法—Kruskal算法 并查集模板 并查集可以实现两个,查找与合并 并查集是一个树的结果,总的还说是森林 可以判断两个结点是否在一个图中,或一个图是否连通 或者实现找朋友题,朋友可以传递,判断谁和谁是否是朋友 房间是否连接 是否为亲戚 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int fa[10005]; int father(int x){ if(fa[x]==x)return x; return fa[x]=father(fa[x]);//动态规划策略,直接 } void unionn(int x,int y){ fa[father(y)]=father(x); } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ fa[i]=i; } for(int i=0;i<m;i++){ int z,x,y; scanf("%d%d%d",&z,&x,&y); if(z==1){ unionn(x,y); }else if(z==2){ printf("%s\n",father(x)=