有权并查集,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
",size[Find_set(c)]-dist[c]-1);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TreeDream/p/5612891.html