有权并查集,Poj(1988)
题目链接:http://poj.org/problem?id=1988
题目大意:
有n个从1到n编号的箱子,将每个箱子当做一个栈,对这些箱子进行p次操作,每次操作分别为以下两种之一:
输入 M x y:表示将编号为x的箱子所在的栈放在编号为y的箱子所在栈的栈顶.
输入 C x:计算编号为x的所表示的栈中在x号箱子下面的箱子数目.
思路:
move a,b的时候(合并的时候),b其中一个作为子树,dist[fb],距离根节点的距离为size[fa],然后size[fa]+=size[fb];
count c的时候,就是size[fa[c]]-dist[c]-1啦。
注意的是:Find_set的时候,要将dist处理好啦,(还是在同一个树中)
if(x!=father[x])
int t=father[x];
father[x]=Find_set[father[x]];
dist[x]+=dist[t];
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> using namespace std; const int maxn = 30000+10; int father[maxn]; int size[maxn]; ///表示团的大小 int dist[maxn]; ///到根节点的距离 int Find_set(int x) { if(x!=father[x]) { int t=father[x]; father[x] = Find_set(father[x]); dist[x]+=dist[t]; } return father[x]; } void Union(int x,int y) { father[y] = x; dist[y] = size[x]; size[x] +=size[y]; } int main() { for(int i=0;i<maxn;i++) { father[i] = i; dist[i] = 0; size[i] = 1; } int t; scanf("%d",&t); getchar(); while(t--) { char order; scanf("%c",&order); if(order=='M') { int x,y; scanf("%d%d",&x,&y); getchar(); int fa = Find_set(x); int fb = Find_set(y); if(fa!=fb) Union(fa,fb); } else { int c; scanf("%d",&c); getchar(); printf("%d\n",size[Find_set(c)]-dist[c]-1); } } return 0; }