并查集的删除操作,可以看做是类似树的懒惰删除,
废弃该节点,但不删除,用根结点记录这个并查集的容量和大小,在节点被废弃后,从它的根节点处删除这个节点的数据
用一个新的节点替换该节点获得其的属性,代替它加入到新的并查集中
可以用一个id[i]数组代替i
Time Limit: 1000MS | Memory Limit: Unknown | 64bit IO Format: %lld & %llu |
Description
![Download as PDF Download as PDF](https://i-blog.csdnimg.cn/blog_migrate/2ea975a8d421ce3226c46b0946fd5932.png)
Problem A
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 7 2 8
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}
#include<stdio.h>
void pn(int a);
void mer(int a,int b);
void move(int a);
int find(int a);
int pre[200005],id[200005],sum[200005],num[200005];
int cn;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
cn=n;
pn(n);
while(m--)
{
int op,p,q,fp;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&p,&q);
mer(id[p],id[q]);
}
else if(op==2)
{
int fp,fq;
scanf("%d%d",&p,&q);
fp=find(id[p]);
fq=find(id[q]);
if(fp!=fq)
{
move(p);
mer(id[p],id[q]);
}
}
else if(op==3)
{
int fp;
scanf("%d",&p);
fp=find(id[p]);
printf("%d %d\n",num[fp],sum[fp]);
}
}
}
return 0;
}
void pn(int a)
{
int i;
for(i=1;i<=a;i++)
{
pre[i]=i;
id[i]=i;
sum[i]=i;
num[i]=1;
}
}
void mer(int a,int b)
{
int fa,fb;
fa=find(a);
fb=find(b);
if(fa!=fb)
{
pre[fb]=fa;
sum[fa]+=sum[fb];
num[fa]+=num[fb];
}
}
int find(int a)
{
int r;
r=a;
while(r!=pre[r])
r=pre[r];
while(a!=pre[a])
{
int z;
z=a;
a=pre[a];
pre[z]=r;
}
return r;
}
void move(int a)
{
int fp;
fp=find(id[a]);
sum[fp]-=a;
num[fp]--;
cn++;
id[a]=cn;
sum[cn]=a;
num[cn]=1;
pre[cn]=cn;
}