【bzoj3376-方块游戏】带权并查集

题意:

n块积木,m个操作或询问。每次移动积木的时候,约翰会选择两块积木X,Y,把X搬到Y的上方。如果X已经和其它积木叠在一起了,那么应将这叠积木整体移动到Y的上方;如果Y已经和其它积木叠在一起了的,假设在Y上方最高处的积木为Z,那么应将X所在的那叠积木移动到Z的上方。
每次询问当前时刻,某一块积木的下方有多少块积木。
n,m<=10^5

 

题解:

带权并查集。
对于每个点x,维护当前所在并查集(也就是这一堆积木中)最下方的积木d[x],最上方的积木fa[x],x到最上方积木的距离f[x],则下方的积木数=f[d[x]]-f[x]。
带权并查集其实就是在findfa的时候顺便维护一些权值。

 

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cmath>
 8 #include<set>
 9 using namespace std;
10 
11 const int N=100100;
12 int n,m,fa[N],f[N],d[N];
13 char s[10];
14 
15 int findfa(int x)
16 {
17     if(fa[x]!=x)
18     {
19         int y=fa[x];
20         fa[x]=findfa(y);
21         f[x]=f[x]+f[y];
22         d[x]=d[y];
23     }
24     return fa[x];
25 }
26 
27 int main()
28 {
29     // freopen("a.in","r",stdin);
30     freopen("cubes.in","r",stdin);
31     freopen("cubes.out","w",stdout);
32     scanf("%d",&m);n=m;
33     int x,y;
34     for(int i=1;i<=n;i++) {fa[i]=i;d[i]=i;f[i]=0;}
35     for(int i=1;i<=m;i++)
36     {
37         scanf("%s",s);
38         if(s[0]=='M') 
39         {
40             scanf("%d%d",&x,&y);
41             int xx=findfa(x),yy=findfa(y);
42             fa[yy]=xx;
43             f[yy]=f[d[x]]+1;
44             d[xx]=d[yy];
45             findfa(d[x]);findfa(d[y]);
46         }
47         else 
48         {
49             scanf("%d",&x);
50             findfa(x);
51             printf("%d\n",f[d[x]]-f[x]);
52         }
53     }
54     return 0;
55 }

 

posted @ 2016-10-28 08:55  拦路雨偏似雪花  阅读(697)  评论(0编辑  收藏  举报