并查集-并查集的删除操作

在并查集中,我们一般做的操作是,把一个集合加入到另一个集合中,从而在查询时,可以高效的查询两个元素的关系。但是有的时候,我们希望可以进行删除操作,就是把一个

点,从一个集合中删除,但是并不影响跟这个点有关系的其他点之间的关系。如图:

当我们删除2号节点后,2号节点成为一个独立的集合,但是,1,3,4号点仍然在一个集合中,如图:

显然,常规的并查集并不能实现这一操作,因此,我们需要另一种写法。常规并查集的初始化的方法是把每个节点的父节点初始化成自己,fa[u]==u,u这个节点就是整个集合的祖宗,此时,u点就有了两重身份:既是一个节点的名字,也是这个集合祖宗的名字,而删除操作的关键就是只改变这一个点的祖宗,而不能改变这个点所在集合的祖宗。因此要把每个节点名字的两重身份分离开,u只表示这个节点的名字,然后给他找一个祖宗(建立虚点),而且,u永远不会是u的祖宗。先给每一个节点建立一个父节点。

void pre(){
    index=n;
    for(int i=0;i<n;i++){
        fa[i]=index++;
    }
    for(int i=n;i<n*2;i++){
        fa[i]=i;
    }
}

0-n-1表示节点的名字,n-n*2-1表示父节点,t点的父节点是t+n号节点。index用于在删除时不断往后扩展新的节点,例如在删除了2号节点后,2号节点是 一个独立的集合,因此它的父节点不能是原来的任何一个节点中,因此fa[2]=index++;

void del(int u){
    fa[u]=index;
    fa[index]=index++;
}

这样做,其他原来跟2同一祖宗的节点的祖宗并没有改变,他们还是连在2号节点原来所连的虚点上,从而实现了删除操作。


例题: 两种操作:M x y将x,y并入一个集合中,S x删除x点,x点成为一个独立的集合,最后求一共有多少个集合。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int readin(){
    int yi=0;
    char c=getchar();
    while(!isdigit(c)){
        c=getchar();
    }
    for(;isdigit(c);c=getchar()){
        yi=yi*10+c-'0';
    }
    return yi;
}
int n,m,fa[1000010],index,dl;
void pre(){
    index=n;
    for(int i=0;i<n;i++){
        fa[i]=index++;
    }
    for(int i=n;i<n*2;i++){
        fa[i]=i;
    }
}
int find(int u){
    if(u==fa[u]) return u;
    return fa[u]=find(fa[u]);
}
void del(int u){
    fa[u]=index;
    fa[index]=index++;
}
void end(){
    int sumn=1;
    for(int i=0;i<n;i++){
        int xi=find(i);
    }
    sort(fa,fa+n);
    for(int i=1;i<n;i++){
        if(fa[i]!=fa[i-1]) sumn++;
    }
    cout<<"Case #"<<dl<<": ";
    cout<<sumn<<endl;
}
void work(){
    char ci;
    int xi,yi;
    for(int i=1;i<=m;i++){
        cin>>ci;
        if(ci=='M'){
            xi=readin();
            yi=readin();
            fa[find(xi)]=find(yi);
        }
        else{
            xi=readin();
            del(xi);
        }
    }
}
int main(){
    while(true){
        dl++;
        n=readin();
        m=readin();
        if(!n) return 0;
        pre();
        work();
        end();
    }
}

猜你喜欢

转载自www.cnblogs.com/wingman/p/10387069.html
今日推荐