第十四届华中科技大学程序设计竞赛 C Professional Manager【并查集删除/虚点】

题目描述 
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



题意:对trees有四种操作。


1 u v,将包含u-th树的森林和含有v-th树的森林合并在一起;

u,将u-th树与森林分开;

3 u,查询包含u-th树的森林的大小;

4 u v,查询u-th树和v-th树是否在同一林中。

【分析】:给每个点都给他们造一个编号w,删除点,就相当于该点的编号w改变就可以了,也是相当于构造新点。

【出处】:UVA 11987 (白书267)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<string>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<set>
#define LL long long
#define INF 0xffffff
using namespace std;
const double pi = 2 * acos (0.0);
const int maxn = 2e5+10;
int n,m;
int p[maxn];
int s[maxn];
int w[maxn];
  
void init()
{
    for(int i=1;i<=maxn;i++) //这里必须是maxn,其他的好像不行
    {
        p[i] = i;
        w[i] = i;
        s[i] = 1;
    }
}
int Find(int x)
{
    return x==p[x]?x:p[x]=Find(p[x]);
}
void Union(int x,int y)
{
    int fx = Find(x);
    int fy = Find(y);
    if(fx!=fy)
    {
        p[fx] = fy;
        s[fy] += s[fx];
        //printf("size=%d\n",s[fy]);
    }
}
  
int main()
{
    int T;
    cin >> T;
    int k =1;
    while(T--)
    {
        printf("Case #%d:\n",k++);
        init();
       
        cin >> n >> m;
        int cnt = n;
        while(m--)
        {
            int op,u,v;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d",&u,&v);
                Union(w[u],w[v]);
            }
            else if(op==2)
            {
                scanf("%d",&u);
                s[Find(w[u])]--;
                w[u] = ++cnt;
            }
            else if(op==3)
            {
                scanf("%d",&u);
                printf("%d\n",s[Find(w[u])]);
            }
            else{
                scanf("%d%d",&u,&v);
                if(Find(w[u])==Find(w[v]))
                    printf("YES\n");
                else printf("NO\n");
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Roni-i/p/8974941.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值