Description
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}
题意:给你三种操作,合并,删点,查询该点所在的集合中元素的个数和所有元素的和
思路:刚开始做,考虑到当删除根节点时,将根节点指向root++,然后再将根节点的孩子指向root
例如:本来1,3 ,4在一个集合(集合最大值为4)现在你想执行2 4 2这个操作,那么你应把4节点删除然后rank[]和sum[]向应的减少,鼓捣了半天竟然超时。 想了想,在建立一个far1【】对根进行操作。思路还是上面的思路,只是当转移的时候,将far1[]中对应的值和你想要删除的点和另一个点重新建立关系,那么原来的那个节点就成了虚点。
#include<iostream>
#include<algorithm>
#include<cstdio>
#define max 100100*2
using namespace std;
int m,n;
int far[max];
int far1[max];
int sum[max];
int rank[max];
int root;
int c,a,b;
void init(int x)
{
for(int i=1; i<=x; i++)
{
far[i]=i;
far1[i]=i;
rank[i]=1;
sum[i]=i;
}
}
int find_set(int n)
{
int tem;
if(n==far[n])
return n;
far[n]=find_set(far[n]);
return far[n];
}
void Union_set1(int a,int b)
{
int x=find_set(far1[a]);
int y=find_set(far1[b]);
if(x==y)
return ;
sum[y]+=sum[x];
far[x]=y;
rank[y]+=rank[x];
}
void Union_set2(int a,int b)
{
int x=find_set(far1[a]);
int y=find_set(far1[b]);
if(x==y)
return ;
int xx=far1[a];
rank[find_set(xx)]--;
sum[find_set(xx)]-=a;
far1[a]=root++;
sum[far1[a]]=a;
rank[far1[a]]=1;
far[far1[a]]=far1[a];
Union_set1(a,b);
}
int main()
{
int ans1,ans2;
int tem;
while(scanf("%d%d",&m,&n)!=EOF)
{
root=m+1;
init(m);
while(n--)
{
scanf("%d",&c);
switch(c)
{
case 1:
scanf("%d%d",&a,&b);
Union_set1(a,b);
break;
case 2:
scanf("%d%d",&a,&b);
Union_set2(a,b);
break;
case 3:
scanf("%d",&a);
tem=find_set(far1[a]);
printf("%d %d\n",rank[tem],sum[tem]);
break;
}
}
}
return 0;
}