题目
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}
输入
5 7
1 1 2
2 3 4
1 3 5
3 4
2 4 1
3 4
3 3
输出
3 12
3 7
2 8
题意
输入 1 a b 将a b所在的集合合并
输入 2 a b 将a 移到b所在的集合里
输入 3 a 输出a所在的集合中 元素的个数 元素的和
思路
我们知道 并查集最终形成的是一个树,树的结构比较复杂
当我们想要把一个元素从节点中取出来时,如果直接改变他的根节点,树就会发生改变,而这不是我们想要的结果
比如 {1,2,3} ,{4}
现在我们要将3和4合并到一个集合中 此时 f[3]=2 ,f[4]=4
如果我们直接令f[3]=4 那么1 和2 的根节点也将发生变化,所以我们不能这样做。所以我们要开一个新的数组 来储存我们每个节点的虚根 id[]数组
当我们要把3节点从第一个集合中取出来时 ,我们令 id[3]=5 而f[3]不变,这样数的结构就不会发生变化了,再进行接下来的操作时,我们对id[]数组进行操作就可以了
代码
#include<stdio.h>
#include<string.h>
int f[1010001],id[1001010],sum[1001000],ans[1000100],n;
void init(int n)
{
for(int i=1; i<=n; i++)
{
f[i]=i;
id[i]=i;
sum[i]=i;
ans[i]=1;
}
}
void pp(int a)
{
int k=++n;
id[a]=k;
f[k]=k;
sum[k]=a;
ans[k]=1;
}
int getf(int u)
{
if(f[u]==u)
return u;
else
{
int x=getf(f[u]);
f[u]=x;
return f[u];
}
}
void merge(int u,int v)
{
int xx=getf(id[u]);
int yy=getf(id[v]);
if(xx!=yy)
{
f[xx]=yy;
sum[yy]+=sum[xx];
ans[yy]+=ans[xx];
}
}
int main()
{
int i,j,k,m,t,a,b;
while(~scanf("%d%d",&n,&t))
{
init(n);
while(t--)
{
scanf("%d",&k);
if(k==1)
{
scanf("%d%d",&a,&b);
if(getf(id[a])==getf(id[b]))
continue;
merge(a,b);
}
if(k==2)
{
scanf("%d%d",&a,&b);//把a移到b中
int x=getf(id[a]);
int y=getf(id[b]);
if(x!=y)
{
ans[x]--;
sum[x]=sum[x]-a;//在这里将它原来所在的根节点的两个数组分别减去相应//的值
pp(a);
merge(a,b);//再合并即可
}
}
if(k==3)
{
scanf("%d",&a);
printf("%d %d\n",ans[getf(id[a])],sum[getf(id[a])]);
}
}
}
return 0;
}