[POJ 1988] Cube Stacking (带值的并查集)

时间:2023-01-10 12:42:56

题目链接:http://poj.org/problem?id=1988

题目大意:给你N个方块,编号从1到N,有两种操作,第一种是M(x,y),意思是将x所在的堆放到y所在的堆上面。 第二种是C(x),意思是数x方块下面有多少个方块。

把两堆合成一堆,这个可以用并查集来实现,问题是,怎么样维护x方块下面有多少个方块呢?

先来分析一下题目,按照样例,我们有6个方块,1,2,3,4,5,6。

令Cnt(x) = C(x)+1。

先执行M(1,6),此时Cnt(1) = 2, Cnt(6) = 1

再执行M(2,4),此时Cnt(2) = 2, Cnt(4) = 1

接下来我们执行M(2,6),此时Cnt(2) = 4, Cnt(4) = 3。

注意到了没有,意思也就是说我们给2和4每一个都增加了Cnt(1)

我们可以利用类似线段树的懒惰标记思想,给方块2加上2点“懒惰值”,然后需要读取4的值的时候,我们再把它统计进来。

由于并查集记录的是父亲节点,因此我们需要把树反着来,也就是说,2摞在6上面,在并查集中,6是2的父亲。

代码:

 #include <cstdio>
#include <algorithm>
#include <bitset>
#include <set>
#include <vector>
#include <iterator>
#include <cstring>
#include <map>
#include <cctype>
using namespace std; const int MAX_N = +;
int f[MAX_N],lazy[MAX_N],sum[MAX_N]; void init(){
for(int i=;i<=MAX_N;i++){
f[i] = i;
lazy[i] = ;
sum[i] = ;
}
} int find(int x){
if( f[x] == x ) return x;
int t = find(f[x]);
lazy[x] += lazy[f[x]];
return f[x] = t;
} void merge(int x,int y){
int fx = find(x) , fy = find(y);
if( fx==fy ) return;
lazy[fx]+=sum[fy];
sum[fy]+=sum[fx];
sum[fx] = ;
f[fx] = fy;
} int main(){
int P,X,Y;
char cmd[];
scanf("%d",&P);
init();
while(scanf("%s",cmd)!=EOF){
if( cmd[]=='M' ) {
scanf("%d%d",&X,&Y);
merge(X,Y);
} else {
scanf("%d",&X);
find(X);
printf("%d\n",lazy[X]);
}
// for(int i=1;i<=P;i++){
// printf("lazy[%d]=%d, sum[%d]=%d\n",i,lazy[i],i,sum[i]);
// }
} return ;
}