POJ 1988 Cube Stacking 带权并查集

Posted 00isok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1988 Cube Stacking 带权并查集相关的知识,希望对你有一定的参考价值。

<题目链接>

题目大意:

有几个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
", son[find(x)]-dis[x]-1);//根节点的子树大小减去x到根节点的距离,再减去x本身
        }
    }
    return 0;
}

 

 

2018-10-03


以上是关于POJ 1988 Cube Stacking 带权并查集的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1988 Cube Stacking 带权并查集

POJ 1988 Cube Stacking(带权并查集)

poj 1988Cube Stacking(图论--带权并查集 模版题)

poj 1988 Cube Stacking

POJ 1988 Cube Stacking

poj1988_Cube Stacking