hdu 2818 Building Block(并查集,有点点复杂)

Building Block

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5811    Accepted Submission(s): 1790

Problem Description
John are playing with blocks. There are N blocks (1 <= N <= 30000) numbered 1...N。Initially, there are N piles, and each pile contains one block. Then John do some operations P times (1 <= P <= 1000000). There are two kinds of operation:

M X Y : Put the whole pile containing block X up to the pile containing Y. If X and Y are in the same pile, just ignore this command. 
C X : Count the number of blocks under block X 

You are request to find out the output for each C operation.
 
Input
The first line contains integer P. Then P lines follow, each of which contain an operation describe above.
 
Output
Output the count for each C operations in one line.
 
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
 
Sample Output
1
0
2
 
Source
Recommend
gaojie   |   We have carefully selected several similar problems for you:  2819 2817 2824 2821 2820 
 
题解:

因为要查询x的下面有多少blocks,所以我们在普通并查集的基础上在维护两个域num[x]和under[x],分别表示x所在堆的大小以及x下面的元素。

在合并的时候,我们分别取x,y的堆的最下面一块,也就是他们的根a,b.a和b相等就不用处理了。如果不相等,那么就让fa[a] = b.而在这之前,我们要维护size和under,所有x原来所在的堆的每个元素的under都要增加num[b],如果全都修改会超时,所以我们之修改under[a],把其它修改放在压缩里面,要查哪一个再更新。同时,为了方便我们只把size存在根上,也就是num[b]+=num[a],num[a] = 0。

在find的时候,我们进行压缩,这时候更新under[x],under[x]+=under[fx]就可以了。

注意:这题一直wa,原因是在刚开始赋值时,应该从0下标开始,然而题目中标号是从1号开始的,不懂。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;
int fa[30005],under[30005],num[30005];
int p;
char ch[5];
int findfa(int k)
{
    if (fa[k]==k) return k;
    int fa1=fa[k]; //找到之前的那个父亲,这个父亲的under值在后面find的过程中也会变,所以只要加之前的父亲节点的under就行了。
    fa[k]=findfa(fa[k]);
    under[k]+=under[fa1];
    return fa[k];
}
void uni(int x,int y)
{
    int fx=findfa(x);
    int fy=findfa(y);
    if (fx!=fy)
    {
       under[fx]+=num[fy];
       num[fy]+=num[fx];
       num[fx]=0;
       fa[fx]=fy;
    }
    return;
}

int main()
{
        for(int i=0;i<30005;i++)
        { fa[i]=i; under[i]=0; num[i]=1;}

        scanf("%d",&p);
        for(;p>0;p--)
        {
            scanf("%s",&ch);
            if (ch[0]=='M')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                uni(x,y);
            } else
            {
                int x;
                scanf("%d",&x);
                findfa(x);
                printf("%d\n",under[x]);
            }
        }

    return 0;
}

 

posted on 2017-07-21 15:00  Yxter  阅读(270)  评论(0编辑  收藏  举报

导航