UVA 11987 Almost Union-Find (带权并查集的操作及并查集的删除操作)
I hope you know the beautiful Union-Find structure. In this problem, you're to implement something similar, but not identical.
The data structure you need to write is also a collection of disjoint sets, supporting 3 operations:
1 p q
Union the sets containing p and q. If p and q are already in the same set, ignore this command.
2 p q
Move p to the set containing q. If p and q are already in the same set, ignore this command
3 p
Return the number of elements and the sum of elements in the set containing p.
Initially, the collection contains n sets: {1}, {2}, {3}, ..., {n}.
Input
There are several test cases. Each test case begins with a line containing two integers n and m (1<=n,m<=100,000), the number of integers, and the number of commands. Each of the next m lines contains a command. For every operation, 1<=p,q<=n. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each type-3 command, output 2 integers: the number of elements and the sum of elements.
Sample Input
5 7 1 1 2 2 3 4 1 3 5 3 4 2 4 1 3 4 3 3
Output for the Sample Input
3 12 3 72 8
题意:给你3种操作。1是将2个集合合并。2是把集合p从原来的集合抽取出来,放入集合q,假设在一起就忽略本命令,3是查询p所在集合的元素个数,跟该集合的元素之和
思路:科普了一下,眼下还没有算法能支持并查集的点直接删除,由于并查集的性质!那么我们能够把抽离出来的点映射到一个新的节点(该节点本身不存在),然后再对原集合进行操作,那么操作其它点的时候就是直接操作每一个点的映射了。
特别注意的是操作2。首先要推断两点是否已经在一起了。不然操作就会错。
AC代码:
#include<cstdio> #include<cstring> typedef long long ll; const int maxn=100000+10; int a[maxn]; int f[maxn*2],tot[maxn]; ll d[maxn]; int find(int x) { if(x!=f[x]) { f[x]=find(f[x]); return f[x]; } else return x; } void Union(int u,int v) { int x=find(a[u]); int y=find(a[v]); if(x==y)return ; d[y]+=d[x]; tot[y]+=tot[x]; f[x]=y; } int main() { #ifndef ONLINE_JUDGE freopen("in.cpp","r",stdin); freopen("out.cpp","w",stdout); #endif // ONLINE_JUDGE int n,m; while(scanf("%d %d",&n,&m)!=EOF) { for(int i=0;i<=n;i++){ f[i]=i; d[i]=i; a[i]=i; tot[i]=1; } //memset(d,0,sizeof(d)); int num=n+1; while(m--) { int k; scanf("%d",&k); if(k==1) { int u,v; scanf("%d %d",&u,&v); Union(u,v); } else if(k==2) { int u,v; scanf("%d %d",&u,&v); if(find(a[u])==find(a[v]))continue; int x=find(a[u]); d[x]-=u; tot[x]--; a[u]=num++; d[a[u]]=u; tot[a[u]]=1; f[a[u]]=a[u]; Union(u,v); } else { int q; scanf("%d",&q); int x=find(a[q]); printf("%d %lld\n",tot[x],d[x]); } } } return 0; }