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;
}

本文深入探讨了并查集结构在处理集合间元素删除和移动操作时的实现细节与优化策略,详细阐述了如何通过映射元素ID来保持集合的连通性和元素归属关系,同时提供了具体代码实现,旨在解决实际应用中常见的数据结构调整问题。
984

被折叠的 条评论
为什么被折叠?



