【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 }