并查集居然是进阶数据结构…我一直觉得他是基础数据结构来着…(等下!它居然是数据结构!)
这可能是所有进阶数据结构里最简单简短简洁的了。七月份的数据结构专题…那些所谓的可持久化点分治我都还没看…(后背一凉)。
概念理论
我个人认为,并查集这个东西,背起来比理解起来真的快多了…跟你扯一大堆没用的理论…还不如你背那么几行代码来的实在…
走个形式。我们可以将并查集看做集合。初始的时候,每个元素各成一集合。在后续的操作中,支持如名称提到的几个功能:
合并:将两个集合合并为一个集合
查询:查找该元素所在集合
所以如果某些东西具有很大的传递性,那么并查集是非常值得考虑的利器。这里就不强调什么路径压缩了…跟着板子背吧。非要弄清楚的话,就手算模拟一下。
代码实现
首先是初始化
void Load(){ for(int i=1;i<=n;i++){ father[i]=i; } }
然后是查
void find(int x){ if(x==fater[x]) return x; return father[x]=find(father[x]); }
最后是并
void Merge(int x,int y){ father[finx(x)]=y; }
之后还有一个边带权的并查集模型。这个模型允许你存储一些每个节点到树根节点之间的路径的一些信息。在后续我会开一个例题来讲解。
边带权并查集
fa[x]表示在第x号战舰前面的那个战舰的编号
d[x]表示在x前面有多少个战舰
size[x]表示在x根上集合的大小
#include<iostream> #include<cmath> using namespace std; const int MAXN=90000; int T; int x,y; char Order; int fa[MAXN]; int size[MAXN]; int d[MAXN]; void Load() { for(int i=1; i<=30000; i++) { fa[i]=i; size[i]=1; } } int Find(int x) { if(x==fa[x]) { return x; } int root=Find(fa[x]); d[x]+=d[fa[x]]; return fa[x]=root; } void merge(int x,int y) { x=Find(x); y=Find(y); fa[x]=y; d[x]=size[y]; size[y]+=size[x]; } int main() { cin>>T; Load(); while(T--) { cin>>Order>>x>>y; if(Order=='M') { merge(x,y); } else { if(Find(x)==Find(y)) { cout<<abs(d[x]-d[y])-1<<endl; } else { cout<<-1<<endl; } } } }
没看数据范围,所以数据范围是瞎开的。其实只是对模板稍作修改就好,谈不上困难。