Professional Manager 并查集

链接: https://www.nowcoder.com/acm/contest/106/C
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

It’s universally acknowledged that there’re innumerable trees in the campus of HUST. 

Thus a professional tree manager is needed. Your task is to write a program to help manage the trees. 
Initially, there are n forests and for the i-th forest there is only the i-th tree in it. Given four kinds of operations.

1 u v, merge the forest containing the u-th tree and the forest containing the v-th tree;

2 u, separate the u-th tree from its forest;

3 u, query the size of the forest which contains the u-th tree;
4 u v, query whether the u-th tree and the v-th tree are in the same forest.

输入描述:

 
  

The first line contains an integer T, indicating the number of testcases.

In each test case:

The first line contains two integers N and Q, indicating the number of initial forests and the number of operations.

Then Q lines follow, and each line describes an operation.

输出描述:

For each test cases, the first line should be "Case #i:", where i indicate the test case i.
For each query 3, print a integer in a single line.
For each query 4, print "YES" or "NO" in a single line.
示例1

输入

1
10 8
3 1
4 1 2
1 1 2
3 1
4 1 2
2 1
3 1
4 1 2

输出

Case #1:
1
NO
2
YES
1
NO

并查集应用,难点在于删除操作,这一个操作影响了整道题目,一般并查集是没有删除操作的,这里出现了,所以这道题还是有点意义的。那么这个删除操作是怎么做的?题目只说了删除,但并没有说删除了这棵树,这棵树属于哪一片森林,所以我们当删除了这个树后,我们直接把这棵树当成一颗新树去处理,利用cur[i]去记录当前位置,所以cur[i]就代表了i所在的位置,如果没有这个cur[i]数组,直接用父节点去替换后面的树的话,那么就变成合并操作了。例如说

1 1 2

2 2

那么第2颗树就就给它新开一个树林,cur[2]=N,这个N代表了新树的位置,所以我们在第二颗树的时候,直接找到cur[2]就可以找到它现在所在的位置了。

我认为,其实这道题就是转移集合的问题。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int father[100009*4];
int sum[100009*4];
int cur[100009*4];
int N;
int Find(int x)
{
    if(father[x]!=x) father[x]=Find(father[x]);
    return father[x];
}
int Union(int a,int b)
{
    int x=Find(cur[a]);//应该是直接当前的下标
    int y=Find(cur[b]);//因为树删除后是会变掉的
    if(x!=y)
    {
        father[x]=y;
        sum[y]+=sum[x];
    }
    return 0;
}
int main()
{
    int t,Count=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,i,j,k,a,b,x,y;
    scanf("%d%d",&n,&m);
    printf("Case #%d:\n",Count++);
    for(i=1; i<=n+m+10; i++)
    {
        father[i]=i;
        cur[i]=i;//当成独立的当前树的位置
        sum[i]=1;
    }
    N=n;
    while(m--)
    {
        scanf("%d",&i);
        if(i==1)
        {
            scanf("%d%d",&a,&b);
            Union(a,b);
        }
        else if(i==2)
        {
            scanf("%d",&a);
            x=Find(cur[a]);
            sum[x]--;
            N++;
            cur[a]=N;
        }
        else if(i==3)
        {
            scanf("%d",&a);
            x=Find(cur[a]);
            printf("%d\n",sum[x]);
        }
        else if(i==4)
        {
            scanf("%d%d",&a,&b);
            x=Find(cur[a]);
            y=Find(cur[b]);
            if(x==y)
            {
                printf("YES\n");
            }
            else
            {
                printf("NO\n");
            }
        }
    }
    }

}


猜你喜欢

转载自blog.csdn.net/keepcoral/article/details/80150242
今日推荐