数据结构进阶——并查集

并查集居然是进阶数据结构…我一直觉得他是基础数据结构来着…(等下!它居然是数据结构!)

这可能是所有进阶数据结构里最简单简短简洁的了。七月份的数据结构专题…那些所谓的可持久化点分治我都还没看…(后背一凉)。

 概念理论

我个人认为,并查集这个东西,背起来比理解起来真的快多了…跟你扯一大堆没用的理论…还不如你背那么几行代码来的实在…

走个形式。我们可以将并查集看做集合。初始的时候,每个元素各成一集合。在后续的操作中,支持如名称提到的几个功能:

合并:将两个集合合并为一个集合

查询:查找该元素所在集合

所以如果某些东西具有很大的传递性,那么并查集是非常值得考虑的利器。这里就不强调什么路径压缩了…跟着板子背吧。非要弄清楚的话,就手算模拟一下。

代码实现

首先是初始化

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;
            }
        }
    }
}

没看数据范围,所以数据范围是瞎开的。其实只是对模板稍作修改就好,谈不上困难。

 题目中的Show Time

说到并查集…印象最深的…一定要说的就是…!

关押罪犯 NOIP2010 提高组

题来!

因为不是写题解,我就不去放我当时惨状的30分爆搜代码了。说实话,当时有点觉得这是个并查集,但也只是隐隐觉得。直到我看到题解中有一个句话

把敌人的敌人关入我的牢笼!关不进去就游戏结束!

即使我现在没看当时的代码…我也记得这个东西的精妙感。把怨气值排个序,然后一个一个来关。如果关不进去,那么就是最大怨气的没关进去,自然就是答案。

即使距离我写这道题都过去很久了…我依然还是想感叹一声!

#include<iostream>
#include<algorithm>
using namespace std;
//思路源自洛谷,完全理解并脱离题解重写。 
const int MAXN=20500;
int a[MAXN];
struct relation{
    int prisonA;
    int prisonB;
    int FireIndex;
}Ships[100400];
int n,m;
int Enemy[MAXN];
inline int find(int x){
    if(a[x]==x){
        return x;
    }
    a[x]=find(a[x]);
    return a[x];
}
inline bool check(int x,int y){
    if(find(a[x])==find(a[y])){
        return true;
    }
    return false;
}
inline bool Ruler(const relation &a,const relation &b){
    return a.FireIndex>b.FireIndex;
}
inline void merge(int x,int y){
    x=find(a[x]);
    y=find(a[y]);
    a[x]=y;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        a[i]=i;
    }
    for(int i=1;i<=m;i++){
        cin>>Ships[i].prisonA>>Ships[i].prisonB>>Ships[i].FireIndex;
    }
    sort(Ships+1,Ships+1+m,Ruler);
    for(int i=1;i<=m+1;i++){
        if(i==m+1){
            cout<<0;
            return 0;
        }
        if(check(Ships[i].prisonA,Ships[i].prisonB)){
            cout<<Ships[i].FireIndex;
            return 0;
        }
        else{
            if(Enemy[Ships[i].prisonA]==0){
                Enemy[Ships[i].prisonA]=Ships[i].prisonB;
            }
            else{
                merge(Enemy[Ships[i].prisonA],Ships[i].prisonB);
            }
            if(Enemy[Ships[i].prisonB]==0){
                Enemy[Ships[i].prisonB]=Ships[i].prisonA;
            }
            else{
                merge(Enemy[Ships[i].prisonB],Ships[i].prisonA);
            }
        }
    } 
} 

 银河英雄传说 NOI2002/CH4101

我在上面把这道题当例题开了,所以请向上翻找一下。

posted @ 2019-07-23 19:36  L1ngYi  阅读(216)  评论(0编辑  收藏  举报