并查集

[Comet OJ - #13] [DQ] [并查集] B C

让人想犯罪 __ 提交于 2019-12-02 14:42:38
C 给定1000*1000的矩阵,每次将一个子矩阵内全部值赋值为1,问四联通块数量 Q 3e4 首先考虑复杂度,3e4次操作的合并暴力肯定不行,并且要考虑已经为1的块不应该再次考虑 1.考虑合并操作,对于一个0点,当他变为1对答案的影响只有几种情况 周边都是0,总联通联通块数量加1 周边有(1 - 4)个不同联通块,ans -= 不同联通块个数+1 对于相同的联通块通过当前0点合并没有意义,不用计算。 所以对于每个0点的合并可以快速计算并用并查集合并(映射下标) 2.然后考虑第二个问题,如何让每个0点只被操作一次 可以用并查集维护每行当前点的下一个0点,这样在区间上跳动速度飞快并且每次跳的都是0点 或者用set维护当前行内还有0的下标并操作erase(比并查集常数大) /* Zeolim - An AC a day keeps the bug away */ //#pragma GCC optimize(2) //#pragma GCC ("-W1,--stack=128000000") #include <bits/stdc++.h> using namespace std; #define mp(x, y) make_pair(x, y) #define fr(x, y, z) for(int x = y; x < z; ++x) #define pb(x) push_back

「佛御石之钵 -不碎的意志-」(hard)

百般思念 提交于 2019-12-02 14:36:15
来源:Comet OJ - Contest #13 一眼并查集,然后发现这题 tmd 要卡常数的说卧槽... 发现这里又要用并查集跳过访问点,又要用并查集维护联通块,于是开俩并查集分别维护就好了 一开始 XJB 搞了两个并查集建了个完全的连接方式,然后 xjb 写了堆合并,调了一会儿交上去喜见 TLE (自闭现场) 挺好的啊,然后改成动态开点并且访问点跳过的操作也优化了一下,终于爬过去了 ORZ 原 Code 代码挺好打&&极不清爽 //by Judge (zlw ak ioi) #include<bits/stdc++.h> #define P pair<int,int> #define fi first #define se second #define Rg register #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i) #define ll long long using namespace std; const int N=1003,M=N*N; typedef int ARR[N][N]; typedef int arr[M]; #ifndef Judge #define getchar() (p1==p2&&

POJ-1182食物链

*爱你&永不变心* 提交于 2019-12-02 12:15:38
题目: 动物王国中有三类动物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 解题思路: 对于每只动物i都需要有3个元素i+A,

[算法模版]种类并查集

谁说我不能喝 提交于 2019-12-02 08:50:11
[算法模版]种类并查集 前言 众所周知,基本的并查集维护很多“集合”,同时可以对集合进行合并操作。而同一集合内的元素性质 完全相等 。但是如果我们不只需要维护相同的元素,还要维护不同元素之间的关系。那我们就可以使用种类并查集来处理。 基本思想 因为同一集合内元素性质 完全相等 ,所以当集合中的一个元素确定了对另一个元素的关系时,我们也确定了这两个元素所在集合之间的关系。而在之前的普通并查集中,两个元素在同一个集合内代表他们 完全相等 。而这里我们需要更改这个规则。 我们先把基础并查集中每个集合的元素都称作 \(A\) 类点,当我们需要维护两个集合之间某种关系时,我们就可以引入一种新的点—— \(B\) 类点。如果两个 \(A\) 类点处于同一集合,就代表他们 完全相等 ,而如果一个 \(A\) 类点和一个 \(B\) 类点处于同一集合,就代表他们是另一种关系。这样我们就可以维护集合间的关系了。 或者换种说法,每个点其实代表了所在集合的“性质”。性质相同的点会被合并。当你需要查找跟当前点是某种关系的集合时,只需要查找对应点所在的集合即可。 例题 NOI2001-食物链 新建立两类点,并给他们分配新的编号来识别种类。 \(B\in[n+1,2n],C\in[2n+1,3n]\) 当一个 \(A\) 类点和一个 \(B\) 类点处于同一集合,则代表 \(A\) 类点可以攻击 \(B\)

并查集和DFS实现船问题(连通性判断)

蹲街弑〆低调 提交于 2019-12-02 06:24:06
题目如下,判断下列矩阵中船的个数(连续的相同数据称为一条船)例如如下矩阵 0 0 1 1 1 1 0 0 0 1 0 0 会输出两条船,这里的两条船分别指的是下图中的粗体部分和斜体部分 0 0 1 1 1 1 0 0 0 1 0 0 那么我们如何做到判断他们的连续情况呢。 方法一DFS法(递归法) DFS方法就是我们所谓的递归方法,我们在考虑一个数据周围的数据是否和他相同,从而实现连通。所以我们最先想到的应该就是一种最暴力的方法: ①先找到一个元素。 ②判断其上下左右的元素是否与他相同,并做出标记。 ③对数组边界作出处理。 这种思维是最简单粗暴的思维,我们从这里切入,对我们的思路进行改善, 我们需要解决如下问题: ①用简洁的代码判断一个数组元素的周围元素是否和他相同 ②对数组边界的处理 ③对已经考虑过的元素进行标记 ④进行计数 好的,下面我们来逐一解决上面四个问题 ①对于一个元素周围的元素是否与他相同,如果我们采用循环的方式,很难准确找到边界,所以我们在这里采用递归的方式,一次判断该元素的上下左右的四个方向的元素,直到找到与这个元素不同的值。 ②对于边界问题,只需要设立好循环次数并且在递归的进入条件中添加边界判定即可 ③对于已经考虑过得元素的标记问题,我这里采用了加入对照数组的方法,即建立一个与给出数组相同长度、相同数组元素的数组。将对照数组中遍历过得数组元素全部赋值为0

吖是“并查集”

泪湿孤枕 提交于 2019-12-02 04:53:43
今天遇到PAT1021,题目中要判断一个图的连通分量数目,一开始想着用 “二维数组存储边的信息+DFS遍历” 来做,后来发现其他题解都用一个叫 “并查集” 的东西来解决分组的问题。 啥是 “并查集” 并查集用来干啥 并查集是用来解决图论中分类问题的一种树形数据结构,常用的就是解决我目前遇到的连通分量的判断问题。 并查集长啥样 并查集就是一个森林,森林里面有很多棵树,我们通过并查集的 “find”(查找) 和 “merge”(合并) 算法来判断将森林里面的树分类。 来源: https://www.cnblogs.com/chuan-chuan/p/11730672.html

codeforces1213G Path Queries 并查集

巧了我就是萌 提交于 2019-12-02 03:43:16
题意 给定n个结点的树,每条边有边权,有m个询问,每个询问给一个 \(q_i\) 输出树上有多少点对的简单路径上最大的边权不超过 \(q_i\) 。 分析 用并查集维护点集,同时维护大小。 将所有边按边权排序,考虑每次从小到大加边,图中经过当前边的所有路径一定是以当前边的边权为最大值的,用并查集维护下图中每个联通块的大小,经过当前边的路径数即为 \(sz[find(u)]*sz[find(v)]\) 。然后前缀和一下就可以 \(O(1)\) 询问了。 Code #include<bits/stdc++.h> #define fi first #define se second #define lson l,mid,p<<1 #define rson mid+1,r,p<<1|1 #define pb push_back #define ll long long using namespace std; const int inf=1e9; const int mod=1e9+7; const int maxn=2e5+10; int n,m; int f[maxn]; ll ans[maxn],sz[maxn]; int find(int k){ if(k==f[k]) return k; else return f[k]=find(f[k]); } struct ppo{ int

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

旧街凉风 提交于 2019-12-02 02:55:13
P3402 【模板】可持久化并查集 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+5; 4 int n, m; 5 int L[maxn*30], R[maxn*30], fa[maxn*30], dep[maxn*30]; 6 int root[maxn*30]; 7 int cnt; 8 void build(int &rt, int l, int r) { 9 rt = ++cnt; 10 if(l == r){ 11 fa[rt] = l; 12 return ; 13 } 14 int mid = (l+r)/2; 15 build(L[rt],l,mid); 16 build(R[rt],mid+1,r); 17 } 18 void merge(int last, int &rt, int l, int r, int pos, int Fa) { 19 rt = ++cnt; 20 L[rt] = L[last], R[rt] = R[last]; 21 if(l == r) { 22 fa[rt] = Fa; 23 dep[rt] = dep[last]; 24 return; 25 } 26 int mid = (l+r)/2; 27 if(pos <= mid)

带权并查集

那年仲夏 提交于 2019-12-02 00:29:09
带权并查集 设cnt[x]为x到本集合代表元素的路径值,在递归寻找代表元素时,如果找到就直接返回,没找到先记录下此时x的fa[x],再让fa[x]被更新,fa[x]被更新也意味着fa[x]到代表元素的cnt[fa[x]]被更新了,则此时再用cnt[fa[x]]更新cnt[x],便完成了路径更新。 核心代码 ~ cpp inline int f(int x) { if(x ^ fa[x]) { int t = fa[x]; fa[x] = f(fa[x]); cnt[x] += cnt[t]; } return fa[x]; } ~ How Many Answers Are Wrong HDU - 3038 题意:给出一个区间的长度 N,及 M 个子区间和, 形如:x y z, 表示子区间 [x, y] 的和为 z 如果一个“子区间和”与前面的“子区间和”冲突,即为错误(而且这个“子区间和”将在接下来的判断中被忽略)。 求总错误个数。 ~~~ include include include include include include include define rint register int define ll long long define lson x<<1 define rson x<<1|1 define mid ((st[x].l + st[x].r) >> 1

并查集 --cogs456 岛国

一世执手 提交于 2019-12-01 23:22:17
题目链接: http://cogs.pro:8081/cogs/problem/problem.php?pid=pNyNQiqge 思路: 基础是并查集,将两个相邻的岛算作一个集合,每次若合并成功,则N--,最终得到的即为答案。 先按读入岛的x1进行升序排序,然后遍历每个节点,对于节点i,取之后的j,并且要求 j 的x1 <= i 的x2 + 1,之后进行判断 判断内容为: 如果i的y2小于j的y1 - 1,或者i的y1大于等于j的y2 + 1,即两块陆地在x坐标上未有交集且不相邻,则return false。 如果i的x2 + 1 == j的x1: 此时,如果i的y2 + 1 == j的y1 说明两块陆地只有一个点相交,return false 否则,就return true 代码如下: #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <algorithm> #define MAXN 10010 using namespace std; int n, ct; int pre[MAXN]; struct Land { int x1, y1, x2, y2; bool operator<(const Land& a)const { if (x1 != a.x1) return