标签:
题目链接: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的父亲。
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <bitset> 4 #include <set> 5 #include <vector> 6 #include <iterator> 7 #include <cstring> 8 #include <map> 9 #include <cctype> 10 using namespace std; 11 12 const int MAX_N = 30000+1; 13 int f[MAX_N],lazy[MAX_N],sum[MAX_N]; 14 15 void init(){ 16 for(int i=1;i<=MAX_N;i++){ 17 f[i] = i; 18 lazy[i] = 0; 19 sum[i] = 1; 20 } 21 } 22 23 int find(int x){ 24 if( f[x] == x ) return x; 25 int t = find(f[x]); 26 lazy[x] += lazy[f[x]]; 27 return f[x] = t; 28 } 29 30 void merge(int x,int y){ 31 int fx = find(x) , fy = find(y); 32 if( fx==fy ) return; 33 lazy[fx]+=sum[fy]; 34 sum[fy]+=sum[fx]; 35 sum[fx] = 0; 36 f[fx] = fy; 37 } 38 39 int main(){ 40 int P,X,Y; 41 char cmd[10]; 42 scanf("%d",&P); 43 init(); 44 while(scanf("%s",cmd)!=EOF){ 45 if( cmd[0]==‘M‘ ) { 46 scanf("%d%d",&X,&Y); 47 merge(X,Y); 48 } else { 49 scanf("%d",&X); 50 find(X); 51 printf("%d\n",lazy[X]); 52 } 53 // for(int i=1;i<=P;i++){ 54 // printf("lazy[%d]=%d, sum[%d]=%d\n",i,lazy[i],i,sum[i]); 55 // } 56 } 57 58 return 0; 59 }
[POJ 1988] Cube Stacking (带值的并查集)
标签:
原文地址:http://www.cnblogs.com/llkpersonal/p/4298383.html