UVA11987(加权并查集)

本文探讨了一种并查集的变体,该变体不仅支持常规的合并操作,还实现了元素移动的功能,通过引入二维状态来实现元素在集合间的灵活转移。详细介绍了其在数据结构中的应用和优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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}


Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Yiming Li

Note: Please make sure to test your program with the gift I/O files before submitting!

本题的难点就在2操作:
要把一个元素从一个集合移到另一个集合。
我们知道并查集是不能删除元素的,因为整个结构是单向的,不知道儿子是什么
但这里移动元素,实际上就蕴含着删除的操作。那该怎么办呢?
有一个想法可能会很快想到,并不实际删除要移动的元素p,即不改变p集合原来的路径,但集合的权值还是要改变(相当于把p看成一个虚点),然后把p直接“挂到”q的集合中去。
注意,这里一定要保证p在以后永远只能作为一个叶子,不能再做父亲,否则会覆盖掉最初(作为父亲时)的路径,并且可以证明只做叶子的做法一定存在。
这样在写程序时要注意的就有以下几点:
1.让每个元素的值有二维状态,一维用于保存,这个元素在最初集合时的情况,另一维保存这个元素现在实际的情况
2.在合并时注意权值的改变,应该用哪一维状态。
3.在find()时先判断这个元素是否真的存在过去和现在两个状态,从而选择搜索的路径不同,并且在写路径压缩时也有些不同。

第一道加权并查集题。。。

92
93
94
95
#include <iostream>
#include <cstdio>
using namespace std;
const int Max = 1e5+5;
long long sum[Max];
int a[Max];
int cent[Max];
int id[Max];
int deep;
void init(int n)
{

    for(int i = 1; i <=  n; i++)
    {
            a[i] = i;
            cent[i] = 1;
            sum[i] = i;
            id[i] = i;
    }
    deep = n;
}

int find(int x)
{
    return a[x] == x ? x :(   a[x] =  find(a[x])   );
}

void Union(int x, int y)
{
    int fx = find(x);
    int fy  = find(y);
          sum[fy] += sum[fx];
          cent[fy] += cent[fx];
          a[fx] = fy;


}

void chang(int x)
{
    int fx = find(id[x]);
    id[x] = ++deep;
    sum[fx] -= x;
    cent[fx] --;
    sum[id[x]] = x;
    cent[id[x]] = 1;
    a[id[x]] =id[x];
}

int main()
{
   int n,m,type,p,q;
    #ifdef xxz
        freopen("in","r",stdin);
    #endif // xxz

    while(scanf("%d%d",&n,&m) != EOF)
    {
        init(n);

        for(int i = 0; i <m; i++)
        {
            scanf("%d",&type);

            if(type == 1)
            {
                scanf("%d%d",&p,&q);
                if(find(id[p]) != find(id[q]))
                Union(id[p],id[q]);

            }
            else if(type == 2)
            {
                    scanf("%d%d",&p,&q);

                    if(find(id[p]) != find(id[q]))
                    {
                           chang(p);
                        Union(id[p],id[q]);

                    }

            }
            else
            {
                    scanf("%d",&p);
                    int fp = find(id[p]);
                    printf("%d %lld\n",cent[fp]  ,  sum[fp] );

            }

        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值