并查集及应用

并查集的应用:

合并两个集合

查询某个元素的祖宗节点

扩展:

记录每个集合的大小(绑定到根节点)

记录每个点到根节点的距离(绑定到每个元素上)

二元或多元判断的时候用到的两种方法:扩展域并查集,带权并查集

常用优化:

路径压缩(find函数,时间复杂度logn)

按秩合并:将树深度小的合并到大的上面(一般超时特别严重才会用)

 1250. 格子游戏(活动 - AcWing)

两人轮流画,谁先封圈谁赢,这里可以用边的双连通分量来判断(因为连的是无向边,但是很显然加一条边tarjan一次太麻烦了,这里可以先记录所有的边,然后二分判断是否封圈,但是这题有更简单的方法)这里从并查集的角度来考虑的话,封圈就意味着,两点之前应该就属于一个集合。那么就很简单了,加一条边找一下祖宗即可。

#include<bits/stdc++.h>
using namespace std;
const int N=200,M=50010;
int n,m;
int p[M];
int find(int x)
{if(p[x]!=x) p[x]=find(p[x]);return p[x];
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=M;i++) p[i]=i;int i;for(i=1;i<=m;i++){int x,y;char op[2];cin>>x>>y>>op;int a,b;a=x*N+y;if(op[0]=='D') b=(x+1)*N+y;else b=x*N+y+1;a=find(a),b=find(b);if(a!=b) p[a]=b;else break;}if(i>m) printf("draw");else printf("%d",i);
}

 1252. 搭配购买(活动 - AcWing)

思路:这里如果买一朵云那么一片云都要买,而且如果买a那么需要买b,同时买b也一定要买a,那么可以把这些连在一块儿的云视为一组,钱有限,价值更高,那么不就是01背包问题。连在一块儿可以用并查集,我们可以把这一片云的价格和价值绑定到根节点上。

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m,w;
int v[N],c[N],f[N],p[N];
int find(int x)
{if(p[x]!=x) p[x]=find(p[x]);return p[x];
}
int main()
{scanf("%d%d%d",&n,&m,&w);for(int i=1;i<=N-1;i++) p[i]=i;for(int i=1;i<=n;i++) cin>>v[i]>>c[i];for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);a=find(a),b=find(b);if(a!=b) {p[a]=b;v[b] += v[a];c[b] += c[a];}//如果本身在一个集合中那么已经累计到根节点了,就不用特殊处理}for(int i=1;i<=n;i++)if(i==p[i])for(int j=w;j>=v[i];j--)f[j]=max(f[j],f[j-v[i]]+c[i]);cout<<f[w];
}

237. 程序自动分析(237. 程序自动分析 - AcWing题库)

这里很容易想到差分约束,但是只有等于不等两个关系,那么我们实际上可以将相等的放入一个集合中,再看有不等关系的点是否在一个集合中即可。

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
struct node{int a,b,e;
}d[N];
int p[N];
int find(int x)
{if(p[x]!=x) p[x]=find(p[x]);return p[x];
}
int n,m;
unordered_map<int,int>mp;
int get(int x)
{if(!mp.count(x)) mp[x]=++n;return mp[x];    
}
int main()
{int t;scanf("%d",&t);while(t--){//清空上一次的状态n=0;mp.clear();scanf("%d",&m);for(int i=1;i<=m;i++){int a,b,e;scanf("%d%d%d",&a,&b,&e);a=get(a),b=get(b);d[i]={a,b,e};}for(int i=1;i<=n;i++) p[i]=i;for(int i=1;i<=m;i++){int a=d[i].a,b=d[i].b,e=d[i].e;if(e){a=find(a),b=find(b);if(a!=b) p[a]=b;}}int flag=1;for(int i=1;i<=m;i++){int a=d[i].a,b=d[i].b,e=d[i].e;if(!e){a=find(a),b=find(b);if(a==b){flag=0;break;}}}if(flag) puts("YES");else puts("NO");}
}

 238. 银河英雄传说(活动 - AcWing)

某一整列接在另一整列后面以及判断两者是否在同一列中是很简单的操作,但是这里还有一个需要求的,就是两者如果在同一列,那么它们之间间隔多少个战舰。这里的处理是记录每个点距离根节点有多少个战舰。那么这个该如何维护呢?我们可以将到根节点的距离视为一条最短路,我们每次合并两个集合就相当于给两个集合的根节点之间加一条边,我们通过给这条边的边权赋值,那么就可以实现维护,每次查找到根节点的最短路即可。

#include<bits/stdc++.h>
using namespace std;
const int N=30010;
int n;
int p[N],d[N],sz[N];
int find(int x)
{if(x!=p[x]){int root=find(p[x]);d[x] += d[p[x]];//这里的更新就是简单的递归,定义root的意义就是保证用到的p[x]值是父节点,保证递归的正确性p[x]=root;}return p[x];
}
int main()
{scanf("%d",&n);for(int i=1;i<N;i++) p[i]=i,d[i]=0,sz[i]=1;while(n--){char op[2];int a,b;cin>>op>>a>>b;int pa=find(a),pb=find(b);//后面要用到a,b,所以这里要用变量单独记录祖先节点的值if(op[0]=='M'){if(pa!=pb){d[pa] += sz[pb];sz[pb] += sz[pa];p[pa]=pb;}//在同一个集合中的不用进行处理}else{if(pa==pb) printf("%d\n",max(abs(d[a]-d[b])-1,0));else printf("-1\n");}}
}

 239. 奇偶游戏(239. 奇偶游戏 - AcWing题库)

思路:这里问是否产生矛盾,那么就需要考虑什么情况下会产生矛盾。显然如果给定[l,k]的奇偶性和给定[k+1,r]的奇偶性,然后再给定[l,r]的奇偶性,三者产生矛盾。这里我们定义s[i]表示前i个数中1的个数,那么对于询问区间,我们就可以知道s[r]与s[l-1]之间的相对奇偶关系。那么相当于我们知道a,b之间和b,c之间的相对就关系,如果访问到a,c判断是否产生矛盾。如果两者不在同一集合中,那么证明之前两者之间没有确定的奇偶关系,我们可以自己加上一个奇偶关系,否则如果两者在同一集合当中就要判断是否产生矛盾。那么如何判断是否产生矛盾,我们可以通过两者与根节点的距离来判断,因为只有奇偶两种情况,我们可以定义只有两种距离0,1,如果奇偶性相同,那么两者之间这一段就为偶,如果奇偶性不同,那么中间这段就为奇。

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m,k;
unordered_map<int,int>mp;
int p[N],d[N];
int get(int x)
{if(!mp.count(x)) mp[x]=++k;return mp[x];
}
int find(int x)
{if(p[x]!=x){int root=find(p[x]);d[x] ^= d[p[x]];p[x]=root;}return p[x];
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<N;i++)p[i]=i;int i;for(i=1;i<=m;i++){int a,b;string s;cin>>a>>b>>s;a=get(a-1),b=get(b);//离散化int pa=find(a),pb=find(b);if(pa==pb)//在同一集合中{if(s=="even"&&!(d[a]^d[b])) continue;else if(s=="odd"&&(d[a]^d[b])) continue;else break;}else{p[pa]=pb;//d[b]就是到根节点的距离,d[a]需要更新成到新节点的距离,那么如何实现呢,显然可以通过更新//a的祖宗节点pa到pb之间的关系,进而实现对d[a]与d[b]关系的更新//实际上d[a]=d[a]^d[pa],d[b]=d[b],要保证的是d[a]和d[b]的相对关系。if(s=="even") d[pa] = d[a]^d[b];else d[pa]=d[a]^d[b]^1;}}printf("%d\n",i-1);
}

因为只有0和1两种距离所以用到异或。

还有一种做法——扩展域

我们将x定义为1-x为偶数,x+n定义为1-x为奇数,而将集合定义成只要在一个集合中,那么一个条件成立,一定集合中所有的条件都成立,这里是用数来表示条件。

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m;
int p[2*N];//每个值有两个点
int find(int x)
{if(x!=p[x]) p[x]=find(p[x]);return p[x];
}
unordered_map<int,int>mp;
int k;
int get(int x)
{if(!mp.count(x)) mp[x]=++k;return mp[x];
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<2*N;i++) p[i]=i;int i;for(i=1;i<=m;i++){int a,b;string s;cin>>a>>b>>s;a=get(a-1),b=get(b);if(s=="even"){if(find(a+N)==find(b)){break;}p[find(a)]=find(b);p[find(a+N)]=find(b+N);}else{if(find(a)==find(b)){break;}p[find(a+N)]=find(b);p[find(a)]=find(b+N);}}printf("%d",i-1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/492345.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎么看伦敦银走势图?这个信号威力无穷.....

伦敦银走势图中的黄金交叉是一种特殊的技术信号&#xff0c;它一般是指较短期的移动平均线向上穿越较长期的移动平均线。在许多情况下&#xff0c;金叉都被视为看涨的信号&#xff0c;因为移动平均线所衡量的是银价在某个时段内的均价——从这个角度看&#xff0c;短期平均线位…

时域离散信号的产生

时域离散信号的产生 函数汇总信号产生 单位抽样序列 \textcolor{plum}{\small \text{单位抽样序列}} 单位抽样序列 单位阶跃序列 \textcolor{plum}{\small 单位阶跃序列} 单位阶跃序列 正余弦序列 \textcolor{plum}{\small 正余弦序列} 正余弦序列 锯齿波三角波序列 \textcolor…

H5多用途的产品介绍展示单页HTML5静态网页模板

H5多用途的产品介绍展示单页HTML5静态网页模板 源码介绍&#xff1a;一款H5自适应多用途的产品介绍展示单页HTML静态网页模板&#xff0c;可用于团队官网、产品官网。 下载地址&#xff1a; https://www.changyouzuhao.cn/13534.html

HTTPS对HTTP的加密过程

1、HTTPS是在HTTP的基础上&#xff0c;引入了一个加密层&#xff08;SSL&#xff09;&#xff0c;对数据进行保护&#xff0c;HTTP 是明文传输的&#xff08;不安全&#xff0c;很可能会被运营商通过referer劫持&#xff0c;或者黑客通过修改链接来窃数据&#xff09; 2、加密…

js:通过input标签或Drag拖拽文件实现浏览器文件上传获取File文件对象

文档 https://developer.mozilla.org/zh-CN/docs/Web/API/Filehttps://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/drag_event 通过读取文件可以获取File对象的信息 lastModified: 1707210706000 lastModifiedDate: Tue Feb 06 2024 17:11:46 GMT0800 (中国标准…

API接口技术开发拼多多API获取宝贝详情页实时数据、原价、销量、主图、优惠券等参数可支持高并发调用接入演示

拼多多的API接口技术可以用于开发能够获取商品详情页实时数据、原价、销量、主图、优惠券等参数的应用程序&#xff0c;并支持高并发调用。以下是一些关于如何实现这一功能的分析&#xff1a; 注册和认证&#xff1a;您需要在开放平台注册账号&#xff0c;并完成必要的实名认证…

Directional coupler and Synchronous optical coupling(定向耦合器和同步光耦合)

Directional coupler and Synchronous optical coupler 正文DC 示意图 正文 DC 示意图 如上图所示是一个 Directional Coupler(DC) 的示意图&#xff0c;当光波从左侧端口进入的时候&#xff0c;会在中间这个直波导部分发生耦合&#xff0c;在一个直波导内的光波会以帅世波的形…

调度服务看门狗配置

查看当前服务器相关的sqlserver服务 在任务栏右键&#xff0c;选择点击启动任务管理器 依次点击&#xff0c;打开服务 找到sqlserver 相关的服务&#xff0c; 确认这些服务是启动状态 将相关服务在看门狗中进行配置 选择调度服务&#xff0c;双击打开 根据上面找的服务进行勾…

Spring Boo项目中方法参数对象中字段上存在的自定义注解如何进行拦截解析

一、前言 在Spring Boot项目开发过程中&#xff0c;我们经常会使用到自定义注解的方式进行业务逻辑开发&#xff0c;此时注解我们一般是放在方法或者类上面&#xff0c;通过AOP切面拦截的方式进行自定义业务逻辑填充。但是如果自定义注解放在类的字段上&#xff0c;此时应该如…

短链接的背后故事:为互联网用户带来的便捷与安全

title: 短链接的背后故事&#xff1a;为互联网用户带来的便捷与安全 date: 2024/2/26 14:58:58 updated: 2024/2/26 14:58:58 tags: 短链接技术起源长URL问题解决链接分享便利性链接跟踪与分析链接管理效率提升链接安全保障应用领域广泛 一、短链接的起源 短链接是一种将长UR…

精益生产,创新驱动:机器人技术引领企业的未来之路

随着自动化技术的普及和物联网、人工智能技术的迅速发展&#xff0c;全球制造业正在经历着一场革命性的变革。传统以人力劳动为基础的制造业正逐渐向以机器为主导的智能生产模式转型。企业们正积极探索更高效的制造方式&#xff0c;通过新兴技术提升生产力&#xff0c;同时降低…