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).
Output
For each type-3 command, output 2 integers: the number of elements and the sum of elements.
Explanation
Initially: {1}, {2}, {3}, {4}, {5}
Collection after operation 1 1 2: {1,2}, {3}, {4}, {5}
Collection after operation 2 3 4: {1,2}, {3,4}, {5} (we omit the empty set that is produced when
taking out 3 from {3})
Collection after operation 1 3 5: {1,2}, {3,4,5}
Collection after operation 2 4 1: {1,2,4}, {3,5}

翻译

有几个测试用例。每个测试用例从一行开始,该行包含两个整数n和m
(1 ≤ n、 m≤ 100000),整数个数 和 命令数
1 p q 并集包含p和q的集合。如果p和q已经在同一个集合中,
忽略此命令。
2 p q 将p移动到包含q的集合。如果p和q已经在同一个集合中,
忽略此命令。
3 p 返回包含元素的集合中元素的数量和元素的总和
P
最初,集合包含n个集合:{1}、{2}、{3}、{n} 。

Sample Input

5 7
1 1 2
2 3 4
1 3 5
3 4
2 4 1
3 4
3 3

Sample Output

3 12
3 7
2 8

解释

最初:{1}、{2}、{3}、{4}、{5}
操作1 1 2 后的集合:{1,2},{3},{4},{5}
操作2 3 4 之后的集合:{1,2},{3,4},{5}
操作1 3 5之后的集合:{1,2},{3,4,5}
操作2 4 1之后的集合:{1,2,4},{3,5}

代码

#include "string.h"
#include "stdio.h"
int a[100000*2+99];//祖先
int sum[100000+9];//集合的和
int su[100000+9];//集合的数量
int idx[100000+9]; //转换量 ,idx[i]的值是i真正的代表值
int n,number;
void ppp()
{
    
    
	for(int i=1; i<=n; i++)
	{
    
    
		a[i]=i;
		sum[i]=i;
		idx[i]=i;//这个数组很重要,下面解释 
		su[i]=1;
	}
	number=n+1;
}
int ff(int x)
{
    
    
	if(a[x]==x) return x;
	return a[x]=ff(a[x]);
}
void change(int x,int ans)   //ans:x以前的祖先
{
    
    
	sum[ans]-=x;
	su[ans]--;
	idx[x]=number++;//idx[x],x的代表值,代表x,
	a[idx[x]]=idx[x];//idx[x]的祖先为idx[x]
	sum[idx[x]]=x;
	su[idx[x]]=1;
}
int main()
{
    
    
	int i,m,j,k,l;
	while(~scanf("%d%d",&n,&m))
	{
    
    
		ppp();
		while(m--)
		{
    
    
			int n1,n2;
			scanf("%d",&k);
			if(k==1)
			{
    
    
				scanf("%d%d",&n1,&n2);
				int m1=ff(idx[n1]);
				int m2=ff(idx[n2]);
				if(m1==m2)
					continue;
				else
				{
    
    
					a[m1]=m2;
					sum[m2]+=sum[m1];
					su[m2]+=su[m1];
				}
			}
			else if(k==2)
			{
    
    
				scanf("%d%d",&n1,&n2);
				int m1=ff(idx[n1]);
				int m2=ff(idx[n2]);
				if(m1==m2)
					continue;
				else
				{
    
    
					change(n1,m1);
					m1=ff(idx[n1]);
					a[m1]=m2;
					sum[m2]+=sum[m1];
					su[m2]+=su[m1];
				}
			}
			else
			{
    
    
				scanf("%d",&n1);
				int m1=ff(idx[n1]);
				printf("%d %d\n",su[m1],sum[m1]);
			}
		}
	}
}

解释,思路

idx[]重要 

两个集合 {1,2,3} {4}

{1,2,3} a[1]=2,a[2]=3,a[3]=3; 大王为 3

{4} a[4]=4 大王为 4

指令:2 2 4  把 2移到包含4的集合中

如果我们直a[2]=4  此时sum[4]=sum[4]+2=6,su[4]=su[4]+1=2
					  sum[3]=sum[3]-2=4,su[3]=su[3]-1=2

两个集合变为 {1,3} {2,4} a[1]=2, a[2]=4, a[3]=3, a[4]=4

指令:3 1; a[1]=2,a[2]=4,a[4]=4,我们会认为 1 的大王为 4
 
  输出 su[4] sum[4] 即  2 6;
   答案明显是错的 应该是  su[3]  sum[3]  即  2  4

所以我们得出a[2]=3 这个我们动不了 但是窝们有需要 2 所以我们就有了 idx[]数组
我们不动a[2]=3,但我们让 2 改头换面 我们让另一个值代替 2 , 进入新的集合
让 数组a[]发现不了,能够正常运行 让 idx[] 穿插在 a[]中

还是上面的例子

两个集合 {1,2,3} {4}

此时 idx[1]=1, idx[2]=2, idx[3]=3, idx[4]=4

{1,2,3} a[idx[1]]=2,a[idx[2]]=3,a[idx[3]]=3; 大王为 3

{4} a[dx[4]]=4 大王为 4

指令:2 2 4  把 2移到包含4的集合中
	
idx[2]=5,a[idx[2]]=5 (即a[5]=5); 2改头换面为 5了 

此时a[idx[2]]=4             sum[4]=sum[4]+2=6,su[4]=su[4]+1=2

(即a[5]=4,5代表的2) sum[3]=sum[3]-2=4,su[3]=su[3]-1=2

两个集合变为 {1,3} {2,4}

指令:3 1;  

idx[1]=1(开始找大王,进入函数)    a[1]=1 ,a[2]=3,a[3]=3;

输出 su[3] sum[3]  即  2  4 

再来一个指令 3 3

idx[3]=5(开始找大王,进入函数)   a[5]=4,a[4]=4; 

输出 su[4] sum[4]  即  2  6 

猜你喜欢

转载自blog.csdn.net/weixin_53623850/article/details/119254552