<题目链接>
题目大意:
有几个stack,初始里面有一个cube。支持两种操作:
1.move x y: 将x所在的stack移动到y所在stack的顶部。
2.count x:数在x所在stack中,在x之下的cube的个数。
解题分析:
由于要实现大量数的移动和归属关系,所以想到可能要用并查集,但是毫无疑问,普通的并查集不能够实现统计在x下的cube个数这一功能,所以我们通过带权并查集来实现,每一个stack,以最高的点为根,然后每一个点维护两个权值,它的子树节点个数(包括它自身),和它到根节点的距离,然后查询x下的cube个数就能够用 son[root(x)]-dis[x]-1来实现,而每个节点到根节点的距离可以在路径压缩的时候更新。
#include <iostream> #include <cstdio> using namespace std; const int M= 3e4+10; int father[M], son[M], dis[M]; //dis表示当前节点到根节点的距离 //son表示当前节点的子树大小(包括该节点本身) int find(int x){ if(father[x]==x){ return x; } int temp=father[x]; father[x]=find(father[x]); dis[x]+=dis[temp]; //x到改变前根节点的距离即x到temp的距离加上temp到根节点的距离 return father[x]; } void Union(int x, int y){ int px=find(x); int py=find(y); if(px!=py){ father[py]=px; //px为py父亲 dis[py]=son[px]; //py到x的根节点的距离为合并之前px的子树大小 son[px]+=son[py]; //更新合并后px的子树大小 } } int main(){ int p; scanf("%d", &p); for(int i=1; i<=M; i++){ father[i]=i; son[i]=1; } for(int i=1; i<=p;i++){ char s[2]; int x, y; scanf("%s", s); if(s[0]==‘M‘){ scanf("%d%d", &x, &y); Union(x, y); //以x原来所在列的根为根 }else{ scanf("%d", &x); printf("%d\n", son[find(x)]-dis[x]-1);//根节点的子树大小减去x到根节点的距离,再减去x本身 } } return 0; }
2018-10-03
原文地址:https://www.cnblogs.com/00isok/p/9740775.html
时间: 2024-09-30 17:33:01