题意:
有N(N<=30,000)堆方块,开始每堆都是一个方块。方块编号1–N.有以下两种操作:M x y :表示把方块x所在的堆,拿起来叠放到y所在的堆上。C x : 问方块x下面有多少个方块。操作最多有P (P<=100,000)次。对每次C操作,输出结果。
输入:
M x y :表示把方块x所在的堆,拿起来叠放到y所在的堆上。
C x : 问方块x下面有多少个方块。
输出:
C的结果。
思路:
除了par数组,还要开设辅助数组:
sum[]:记录每堆一共有多少方块,若par[a] = a, 则sum[a]表示a所在的堆的方块数目。
under[] :under[i]表示第i个方块下面有多少个方块。under数组在堆合并和路径压缩的时候都要更新。
小结:并查集有两种,一种是关系式,一种是数量式。这里是后者。需要开辅助数组求解。
闲话二三:
这些天事情真多,写着写着总是错,参考着前人的,终于A掉了。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=30050;
int sum[N],under[N],par[N];
void init();
void merge(int a,int b);
int find_set(int a);
int query(int a);
int main(){
int p;
scanf("%d",&p);
init();
while(p--){
char op;
int x,y,i;
scanf("\n%c",&op);//这种读入方式要学习
if(op=='M'){
scanf(" %d %d",&x,&y);
merge(x,y);
}
else{
scanf("%d",&x);
find_set(x);
printf("%d\n",under[x]);
}
}
return 0;
}
void init(){// ok
for(int i=1;i<=N;i++){
par[i]=i;
sum[i]=1;
under[i]=0;
}
}
void merge(int a,int b){// C a b
a=find_set(a);
b=find_set(b);
if(a==b) return;
par[a]=b;
//sum[b]=sum[a];
under[a]+=sum[b];//这个函数容易出错,因为a,b相互的操作。并非纯并查集模版类型的操作。
sum[b]+=sum[a];
}
int find_set(int a){
int tmp=par[a];
if(par[a]!=a){
par[a]=find_set(par[a]);
under[a]+=under[tmp];
}
return par[a];
}