标签:函数 user upload char mes 单元 集合 数据量 国际
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。 (摘自百度)
关于并查集和路径压缩:
现在我们假定 f[i]
表示第 i 个人的老大是谁。
现在我们有甲,乙,丙三个人(分别用 a, b, c 表示)
假设甲和乙打架了,甲做了丙的小弟。则有 f[a]=b
,
后来甲打赢了丙
那么丙就是甲的小弟了。有 f[c]=a
,
但是如果我们这样表示,丙不能直接知道甲,容易自己人打自己人
所以,我们必须直接让丙的大哥变成最大的老大。
定义函数 find
int find(int k){
if(f[k]==k)return k;
return find(f[k]);
}//find 函数可以直接找到最大的老大
f[c]=find(a);
//丙的老大是甲
这时,因为我们要路过他所有的上级,我们也可以顺便使途中经过的人的大哥也变成老大。
//路径压缩
int find(int k){
if(f[k]==k)return k;
return f[k]=find(f[k]);
/*
即:
f[k]=find(f[k]);
return f[k];
*/
}
f[c]=find(a);
简直是太巧妙了!
而判定两个人的老大是否相等,只需
if(find(a)==find(b))
就好了。
一些设定:
AC代码:
#include<bits/stdc++.h> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘) f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } int n,m; int fa[5020000]; int find(int x) { if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void ans(int x,int y) { if(find(x)==find(y)) printf("Y\n"); else printf("N\n"); } void hebing(int x,int y) { fa[find(x)]=find(y); } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int opt,x,y; opt=read();x=read();y=read(); if(opt==1) { hebing(x,y); } else { ans(x,y); } } return 0; }
感谢巨神@ huangzirui
标签:函数 user upload char mes 单元 集合 数据量 国际
原文地址:https://www.cnblogs.com/yxr001002/p/14063128.html