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}
本题核心的是并查集的删除,按通常的并查集的做法,集合用某一元素的值表示,若删除此元素,则此元素所在的集合无法寻求根元素。
为解决这个问题,将元素映射为一个id,集合的根用id表示,某一个元素删除后跟存储的是id所以集合任仍在,当某一元素添加到一个集合中是,为该元素分配一个唯一确定的id。以区别在被删除集合中的该元素的id.
#include <iostream>
#include "stdio.h"
using namespace std;
const int MAX = 2000000+10;
int r[MAX],id[MAX/2],size[MAX],sum[MAX],cnt;
int find_r(int p)
{
if(r[p] == p)return p;
return r[p] = find_r(r[p]);
}
void uni(int p, int q)
{
int rp = find_r(id[p]);
int rq = find_r(id[q]);
if(rp != rq)
{
r[rp] = rq;
size[rq] += size[rp];
sum[rq] += sum[rp];
}
}
void move(int p, int q)
{
int rp = find_r(id[p]);
int rq = find_r(id[q]);
--size[rp];
sum[rp] -= p;
id[p] = ++cnt;
r[cnt] = rq;
sum[rq] += p;
++size[rq];
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m) != -1)
{
for(int i = 1; i <= n; i++)
{
r[i] = i;
size[i] = 1;
sum[i] = i;
id[i] = i;
}
cnt = n;
int symb,p,q;
while(m--)
{
scanf("%d",&symb);
if(symb == 1)
{
scanf("%d%d",&p,&q);
uni(p,q);
}
else if(symb == 2)
{
scanf("%d%d",&p,&q);
move(p,q);
}
else if(symb == 3)
{
scanf("%d",&p);
int f = find_r(id[p]);
printf("%d %d\n",size[f],sum[f]);
}
}
}
//cout << "Hello world!" << endl;
return 0;
}