首页 > 其他分享 >并查集学习指南

并查集学习指南

时间:2023-10-16 18:34:06浏览次数:35  
标签:学习指南 return int sum 查集 fa 账本 find

前置芝士

并查集思想

[find]

[python]

#python while
def find(x:int)->int:
	while x!=fa[x]:
		x=fa[x]=fa[fa[x]]
	return x
#python 递归
def find(x:int)->int:
	if fa[x]!=x:
		fa[x]=find(fa[x])
	return fa[x]

[c++]

//c++ while lambda  
/*function<int(int)> find=[&](int x){}   */
    auto find=[&](int x){
        while(x!=fa[x]) x=fa[x]=fa[fa[x]];
        return x;
    };

带权并查集

狡猾的商人

【题目描述】

刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了 n 个月以来的收入情况,其中第 i 个月的收入额为 a_i,i=1,2,,n1,n。当 ai>0 时表示这个月盈利ai元,当ai<0 时表示这个月亏损ai元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。刁姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。

现在,姹总共偷看了m 次账本,当然也就记住了m 段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。

【输入描述】

第一行为一个正整数 w,其中 w<100,表示有 w 组数据,即 w 个账本,需要你判断。

每组数据的第一行为两个正整数 nm,其中 n<100,m<1000,分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。

接下来的 m 行表示刁姹偷看 m 次账本后记住的 m 条信息,每条信息占一行,有三个整数 s,tv,表示从第 s 个月到第 t 个月(包含第 t 个月)的总收入为 v,这里假设 s 总是小于等于 t

【输出描述】

包含 w 行,每行是 truefalse,其中第 i 行为 true 当且仅当第 i 组数据,即第 i 个账本不是假的;第 i 行为 false 当且仅当第 i 组数据,即第 i 个账本是假的。

【解题思路】

如何确定合并两个集合时更新到祖宗节点距离的更新方式。

我们不妨先来看这样一个例子,现有结点1,2,3,4有p[1]=3,p[2]=4,d[1]=10,d[2]=30。

img

d[3]=w(3→1)+w(1→2)+w(2→4)=−d[1]+w+d[2]

如果要添加一条边x→wy(x<y)(将x合并到y),距离更新方式如下d[find(x)]=−p[x]+w+d[y]。

如果要添加的这条边的两个端点已经位于同一个集合中,则直接判断d[x]−dy是否与w相等即可,如果不相等则可判定当前账本存在问题。

最后注意一点 从s到t月份的金钱不是sum[t]-sum[s](这是算得s+1到t的金钱),应该是sum【t】-sum【s-1】 (前缀和思想)。

int fa[1010],sum[1010],n,m,flag;
int find(int x){
	if(fa[x]==x) return fa[x];
	int tmp=find(fa[x]);
	sum[x]+=sum[fa[x]];
	return fa[x]=tmp;
}
void merge(int x,int y,int z){
	int fx,fy;
	fx=find(x);
	fy=find(y);
	if(fx!=fy){
		fa[fy]=fx;
		sum[fy]=sum[x]-sum[y]+z;
	}else{
		if(sum[y]-sum[x]!=z)
			flag=true;
	}
}
void init(int n){
	for(int i=0;i<=n;i++){
		fa[i]=i;
		sum[i]=0;
	}
	flag=false;
}
void solve(){
	int x,y,z;
	cin>>n>>m;
	init(n);
	for(int i=1;i<=m;i++){
		cin>>x>>y>>z;
		x--;
		merge(x,y,z);
	}
	if(flag) cout<<"false"<<endl;
	else cout<<"true"<<endl;
}

标签:学习指南,return,int,sum,查集,fa,账本,find
From: https://www.cnblogs.com/taotao123456/p/17768063.html

相关文章

  • [算法分析与设计] 3. 并查集分析与反阿克曼函数
    Union-Find问题:给定\(n\)个元素,最初每个元素在一个集合中,有两种操作,union表示合并两个集合,find表示查询某个特定元素所在的集合。并查集是一种数据结构。其为每个集合寻找一个代表元,代表元可以是任意的,也可以随操作变化,但需要满足任何时刻一个集合的代表元是确定且唯一的。......
  • 并查集
    并查集如果有一个关系网,我们需要建立两点之间的关系,如果仅用一维链表,则有可能无法考虑到两点同为一点“儿子”的情况,则我们需要建立一个方式,从而直接对比两点“祖父”。一.递归查询intfind(intx){ if(fa[x]==x)returnx;//只有祖父自环,如果他也自环,则找到父节点 ......
  • 线段树高阶学习指南
    前置芝士线段树基本框架区间求和constintN=100010;lla[N],st[N*4],f[N*4];intn,q;//向上传voidpushup(llu){st[u]=st[lc]+st[rc];}//向下传voidpushdown(llu,lll,llr,llmid){if(f[u]){st[lc]+=f[u]*(mid-l+1);st[rc]+=f[u]*(r-m......
  • Ubunte技术学习指南
    安装gcc并检测终端命令sudoaptinstallgccgcc--version//查看版本号,检测是否正确安装创建.c文件touchtest.cvimtest.c//进入vim,进行编程序,退出:进入命令指令系统,:wqgcctest.c//生成a.out./a.out//运行c语言程序......
  • 并查集的实现【学习算法】
    并查集的实现【学习算法】前言版权推荐并查集的实现最后前言2023-9-2614:38:02以下内容源自《【学习算法】》仅供学习交流使用版权禁止其他平台发布时删除以下此话本文首次发布于CSDN平台作者是CSDN@日星月云博客主页是禁止其他平台发布时删除以上此话推荐算法讲解056【必备】并......
  • 《MySQL与MariaDB学习指南》高清高质量 原版电子书PDF+源码
    下载:https://pan.quark.cn/s/2392eb287424......
  • 基环树学习指南
    基环树学习指南前置芝士一个图中包含n个点n条边,且图中只存在一个环,这样的图被称为基环树(环套树)。基环树比树多了一条边,从而形成了一个环。基环树可以看做以坏点为根的一颗颗子树构成。三大分类基环无向树基环内向树(每个点有且只有一条出边)基环外向树(每一个点只有一条入边)[......
  • 并查集
    基本的并查集OI-wikiLink并查集,一种用于管理元素所属集合的数据结构,形如一片森林,同一棵树内的元素所属同一集合,不同树内的元素不属于同一集合。将并查集拆分一下。并,合并;查,查询;集,处理的是集合相关内容。所以并查集一共有两种操作:合并两元素对应集合、查询某元素所属集合(查......
  • 数据结构-并查集
    并查集的使用范围:1.合并集合2.查询两元素是否属于同一集合   高级用法:  3.进行集合划分<带权并查集>  4.连通块块数查询&块内元素个数统计<连通图>  5.撤销合并<可持久化并查集>//本文暂不涉及,我还不会并查集基本操作:#definerep(i,n)for(int......
  • 线段树分治&可撤销并查集
    可撤销并查集按时间顺序用一个栈维护合并信息,撤销时从栈顶弹出合并信息,恢复原状态。并查集查找祖先时不能路径压缩,只能按秩合并。例题:[ABC302Ex]BallCollector容易想到将\(A_i\)和\(B_i\)之间连边。遍历整棵树,用可撤销并查集维护图。为了进一步求得答案,需要注意到该......