杭电 2818 Building Block(题解+代码)

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2818
题目:

Building Block
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

题意:
  John在玩积木。总共有N个积木(1<=N<=30000),从1命名到N。起初,一共有N堆,并且每堆只有一块积木。接着John开始做P次操作。操作分别有两种,如下:
  M X Y:把包含X的积木堆叠在包含Y的积木堆上面,如果X和Y在同一个堆,则忽略这个操作。
  C X:计算积木X下面的积木数量
  要求是输出每个C操作。

题解:
  利用有权并查集进行计算,sum数组保存各个堆的大小,under数组保存积木X下方的积木数量。
  输入M X Y时,分别寻找X与Y的祖先,然后“X的祖先”堆下方的积木数量为 “Y堆的祖先” 积木总数量,Y堆的积木总数量需要加上X堆的积木总数量。
  输入C X时,需要更新一次X下方的积木总数量。然后输出under [ x ]

需要注意的是,题目有一个坑点,数组初始化要从0开始不能从1开始,否则会WA
代码及注释如下:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dis[30005],sum[30005],under[30005];
int getf(int a) {
    if(a==dis[a]) return a;
    int ans=getf(dis[a]);
    //调用原函数,更新under数组 
    under[a]+=under[dis[a]];
    dis[a]=ans;
    return dis[a];
}
void merge(int a,int b) {
    int t1=getf(a);//a的祖先 
    int t2=getf(b);//b的祖先 
    if(t1!=t2) {
        under[t1]=sum[t2];
        //t1下方的积木数量为t2积木堆的总数 
        sum[t2]+=sum[t1];
        //t2积木堆的总数量要加上t1堆的数量 
        dis[t1]=t2;
        //t1的祖先更新为t2 
    }
}
int main() {
    int n,a,b;
    char ch;
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0;i<30005;i++) {//初始化从0开始
        dis[i]=i;
        under[i]=0;
        sum[i]=1;
    }
    for(int i=0;i<n;i++) {
        cin>>ch;
        if(ch=='M') {
            cin>>a>>b;
            merge(a,b);//合并操作 
        }
        if(ch=='C') {
            cin>>a;
            getf(a);//更新under数组 
            cout<<under[a]<<endl;
        }
    }
    return 0;
}

ac图片

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值