并查集

并查集模板

匿名 (未验证) 提交于 2019-12-02 23:34:01
Code: #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> using namespace std; int n,m,bz; int father[200001]; int find(int x) { if(x==father[x]) return x; return father[x]=find(father[x]); } void unnio(int x,int y) { father[y]=x; } inline int read() { bool f=0; int x=0; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=!f; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return f?-x:x; } inline void write(int x) { if(x<0) { putchar('-'); write(-x); } else { if(x/10) write(x/10); putchar(x%10+'0'); } } int main() {

并查集对状态的维护

匿名 (未验证) 提交于 2019-12-02 23:34:01
版权声明:本人所有 https://blog.csdn.net/mxYlulu/article/details/89881514 这里的题目一般都是维护状态,每个集合表示的是一种状态(一般为两个) 题目会询问第一次状态冲突的时候[并查集添加状态的时候发现已有状态并且状态不对] 数据结构K题 K题讲述的是:告诉你n个区间的和的奇偶,判断第一个矛盾的地方。 区间和的奇偶可以转换成可以维护的前缀和之差的奇偶,和为奇,前缀和sum[l-1]和sum[r]一定奇偶不同。 前者奇后者偶,或者反过来。这两种状态我们都添加到并查集里去。 那么怎么表示哪个是奇数呢,0~n为奇数,n+1~2*n+1为偶数。类似于罪犯分配问题。后者做过的前提我还没做出来K题,看到题解才恍然大悟,脑子不行就要靠刷题弥补。 #include<bits/stdc++.h> #define FOR(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int MAXN = 1000050*2; int n,m; int f[MAXN]; struct UnionSet { UnionSet(int n) { for (int i = 0; i <= 2*n+1; i++) { f[i] = i; } } UnionSet(){}

数据结构之并查集

匿名 (未验证) 提交于 2019-12-02 23:34:01
什么是并查集 并查集是个 神奇的 树型的数据结构,多用于查看几个元素是否有关系,一般并查集构造成下图: 由此我们可以很容易地知道2和6是联通(有关系)的,因为他们他们的父亲都是1 并查集的用处 在一些有N个元素的集合应用问题中,通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,所以只能用并查集来描述。 如何构造和维护并查集 以下图举例 初始化 把每个点所在集合初始化为其自身。 通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。 int fa [ 10010 ] for ( int i = 1 ; i <= n ; i ++ ) { fa [ i ] = i ; } //相当于自己就是自己的根 于是乎 查找 查找元素所在的集合,即根节点。 int get ( int x ) { //用dfs往上走即可 if ( fa [ x ] == x ) { //已经找到根 return x ; } else

【并查集】家谱

匿名 (未验证) 提交于 2019-12-02 23:34:01
家谱 题目 现代的人对于本家族血统越来越感兴趣, 现在给出充足的父子关系, 请你编写程序找到 某个人的最早的祖先。 输入 输入文件由多行组成, 首先是一系列有关父子关系的描述, 其中每一组父子关系由二行 组成,用#name 的形式描写一组父子关系中的父亲的名字,用+name 的形式描写一组父子关 系中的儿子的名字;接下来用?name 的形式表示要求该人的最早的祖先;最后用单独的一个 $表示文件结束。规定每个人的名字都有且只有 6 个字符,而且首字母大写,且没有任意两 个人的名字相同。最多可能有 1000 组父子关系,总人数最多可能达到 50000 人,家谱中的 记载不超过 30 代。 输出 按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式:本人的名字+一个 空格+祖先的名字+回车。 输入样例#George + Rodney #Arthur + Gareth + Walter #Gareth + Edward ? Edward ? Walter ? Rodney ? Arthur $ 输出样例 Edward Arthur Walter Arthur Rodney George Arthur Arthur 解题思路 其实就是用并查集来连接父子节点,然后统计即可. 程序如下 # include <iostream> # include <algorithm> # include

The 2017 ACM-ICPC Asia Beijing Regional Contest

匿名 (未验证) 提交于 2019-12-02 22:59:29
地址 Rank Solved A B C D E F G H I J 51/384 4/10 . . . O O . O . O O : 当场通过 : 赛后通过 . : 尚未通过 A Domains unsolved B K-Dimensional Foil unsolved C Graph upsolved by chelly chelly's solution 很显然的思路就是莫队+并查集 但众所周知并查集可以支持可撤销,但不是很好支持可持久化 于是就可以用上回滚莫队的套路了,回滚莫队可以把一般莫队的删除操作变成撤销操作,复杂度不改变 于是这题用回滚莫队+可撤销并查集即可解决 注意回滚莫队的时候,处理右半边的点的时候,不能连向左半边的点,否则rollback的时候跨越中间的边并没有撤销 D Chinese Checkers unsolved E Cats and Fish solved by chelly chelly's solution F Secret Poems solved by chelly chelly's solution G Liaoning Ship’s Voyage unsolved H Puzzle Game solved by chelly chelly's solution I Colored Nodes unsolved J Pangu and

带权并查集

假装没事ソ 提交于 2019-12-02 22:36:14
带权并查集 啦啦啦 太厉害了 就是合并的时候加个权值,找祖父时加个权值。 找祖父 int find(int a) { if(a!=fa[a]) { int t=fa[a]; fa[a]=find(fa[a]); val[a]+=val[t]; // 跟新 这个节点到 祖父的 权值 } return fa[a]; } 合并 int l=find(a); int r=find(b); if(l!=r) { fa[l]=r; val[l]=-val[a]+c+val[b]; //跟新权值 } else { if(val[a]-val[b]!=c) ans++;// 解决问题 小的节点到 祖父的权值 大 } } 例题: HDU-3038-How Many Answers Are Wrong 这个题题目的废话比较多,这里简述一下大意:有M个数,不知道它们具体的值,但是知道某两个数之间(包括这两个数)的所有数之和,现在给出N个这样的区间和信息,需要判断有多少个这样的区间和与前边已知的区间和存在矛盾。例如给出区间和[1,4]为20,[3,4]为15,再给出[1,2]为30,显然这个[1,2]的值就有问题,它应该为20-15=5。 View Code 代码: #include <bits/stdc++.h> using namespace std; #define ri register int

(贪心+并查集综合)[POJ1456] Supermarket

泄露秘密 提交于 2019-12-02 19:08:16
Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 20725 Accepted: 9192 Description A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell ≤ Prod such that the selling of each product x∈Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling

并查集,dfs

ぃ、小莉子 提交于 2019-12-02 16:48:22
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 int edge[55][55],d[55]; 7 8 void dfs(int mid) //寻找连通块 9 { 10 for(int k=1;k<=50;k++) 11 { 12 if(edge[mid][k]) 13 { 14 edge[mid][k]--; 15 edge[k][mid]--; 16 dfs(k); 17 printf("%d %d\n",k,mid); //一定要逆序输出,这样得到的才是答案 18 } 19 } 20 return; 21 } 22 int main(void) 23 { 24 int t,n,t0,i,j,x,y; 25 scanf("%d",&t); 26 for(t0=1;t0<=t;t0++) 27 { 28 memset(edge,0,sizeof(edge)); 29 memset(d,0,sizeof(d)); 30 scanf("%d",&n); 31 for(i=0;i<n;i++) 32 { 33 scanf("%d%d",&x,&y); 34 edge[x][y]++; 35 edge[y][x]++; 36 d[x]++; 37 d[y]++;

任意点------并查集

一世执手 提交于 2019-12-02 15:22:03
传送门 方法就是在同一行的是一个集合,在同一列的也是一个集合,先存再一个一个枚举即可。 这里主要就是要注意,当所有的点都已经全部连接完毕之后,编号为i的点的祖先并不是fa[i],而是fin(i),因为最后还要进行一次预处理,将所有的点都重新整合一遍(防止出现类似于,1,2,3,4,5是一个集合,那么可能fa[1]=1,fa[2]=1,fa[3]=2,fa[4]=3,fa[5]=3这种情况) # include <bits/stdc++.h> using namespace std ; const int MX = 1e3 + 9 ; int n , fa [ MX ] , pos [ MX ] ; vector < int > vh [ MX ] , vl [ MX ] ; int fin ( int u ) { return fa [ u ] = ( fa [ u ] == u ? u : fin ( fa [ u ] ) ) ; } void link ( int u , int v ) { u = fin ( u ) ; v = fin ( v ) ; if ( u != v ) { if ( u < v ) fa [ v ] = u ; else fa [ u ] = v ; } } int main ( ) { // freopen("input.txt","r"

[Codeforces1250E] The Coronation

纵饮孤独 提交于 2019-12-02 15:11:38
[Codeforces1250E] The Coronation The Coronation 又是一道并查集。。。最近做的并查集咋这么多。。。 思路 首先,维护元素间关系的题想到并查集。 因为这里涉及到“翻转”操作。所以我们把反转过后的点 \(i\) 设为 \(i'\) ,令 \(i'=i+n\) 。然后使用拆点并查集来计算。 我们把需要同时满足的条件放入一个并查集。然后对于任意两个串,都有四种情况: 两个串无论转不转都不相似,显然无解,直接输出-1即可。 两个串无论转不转都相似,因为这两个串之间没有相互牵制的限制,所以不管。 两个串相似当且仅当其中一个翻转。那么这时候将 \(i,j+n\) 合并,将 \(j,i+n\) 合并。(代表了如果取 \(i\) , \(j+n\) 必须取,反之亦然) 两个串相似当且仅当没有一个翻转,那么这时候将 \(i,j\) 合并,将 \(i+n,j+n\) 合并。(理由同上) 这样我们就维护了并查集之间的关系。而题目求的就是在满足上述条件情况下,把所有字母代表的点都取到,形如 \(i'\) 的字母取的最少。我们可以给并查集加权来维护这个东西。 又因为对于 \(i\) 处于的集合,这个集合和 \(i'\) 所在的集合的唯一区别是所有字母取反( \(i\) 变成 \(i'\) , \(i'\) 变成 \(i\) )。 所以对于这两个集合,无论取哪个