题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2818
题目:
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;
}