洛谷UVA11987Almost Union-Find题解--并查集的删除

题目链接

https://www.luogu.org/problemnew/show/UVA11987

分析

分析下操作发现就是加了个删除操作的并查集,怎么做删除操作呢.

我们用一个\(id[]\)记录每个数字在并查集中的编号,\(tot=n\),一开始\(id[i]=i\),当将\(p\)从原集合中删除时,让原来的\(id[p]\)变成一个虚点,\(id[p]=++tot\),这样就完成了删除操作,当然我们查找祖先时需要\(find(id[x])\)

推荐博客:https://blog.csdn.net/grimcake/article/details/77115078

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <cmath>
#define ll long long 
#define ri register int 
using namespace std;
const int maxn=200005;
const int inf=0x7fffffff;
template <class T>inline void read(T &x){
   x=0;int ne=0;char c;
   while(!isdigit(c=getchar()))ne=c=='-';
   x=c-48;
   while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
   x=ne?-x:x;
   return ;
}
int size[maxn],id[maxn],sum[maxn],fa[maxn],tot=0;
int find(int x){
   return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
int n,m;
int main(){
   int opt,p,q,x,y;
   while(scanf("%d %d",&n,&m)!=EOF){
   	tot=n;
   	for(ri i=1;i<=n;i++){
   		size[i]=1;
   		fa[i]=id[i]=sum[i]=i;
   	}
   	while(m--){
   		read(opt);
   		if(opt==1){
   			read(p),read(q);
   			p=find(id[p]),q=find(id[q]);
   			if(p==q)continue;
   			fa[p]=q;
   			sum[q]+=sum[p];
   			size[q]+=size[p];
   		}
   		else if(opt==2){
   			read(p),read(q);
   			x=find(id[p]),y=find(id[q]);
   			if(p==q)continue;
   			id[p]=++tot;
   			fa[id[p]]=y;
   			sum[y]+=p,size[y]++;
   			size[x]--,sum[x]-=p;
   		}
   	    else{
   			read(p);
   			x=find(id[p]);
   			printf("%d %d\n",size[x],sum[x]);
   		}
   	}
   }
   return 0;
}

posted @ 2018-07-17 19:24  Rye_Catcher  阅读(287)  评论(0编辑  收藏  举报