• 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 <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int M =3e4+10;
    int father[M+10],son[M+10],dis[M+10];
    //dis表示当前节点到根节点的距离
    //son表示当前节点的子树大小(包括该节点本身)
    int find(int x){
        if(father[x]==x)return x;
        int tmp=father[x];
        father[x]=find(father[x]);
        dis[x]+=dis[tmp]; //x到改变前根节点的距离即x到temp的距离加上temp到根节点的距离
        return father[x];
    }
    void Union(int x,int y){
        int f1=find(x),f2=find(y);
        if(f1!=f2){
            father[f2]=f1;   //f1为f2的父亲 
            dis[f2]=son[f1]; //f2到根节点的距离(f1)为f1的子树的大小 
            son[f1]+=son[f2];//更新f1子树的大小 
        }
    }
    int main(){
        int q;scanf("%d",&q);
        for(int i=0;i<=M;i++){
            father[i]=i;
            son[i]=1;
            dis[i]=0;
        }
        char s[10];
        while(q--){
            scanf("%s",s);
            if(s[0]=='M'){
                int a,b;
                scanf("%d%d",&a,&b);
                Union(a,b);  //以x原来所在列的根为根
            }
            else{
                int a;
                scanf("%d",&a);
                printf("%d
    ",son[find(a)]-dis[a]-1);  //根节点的子树大小减去x到根节点的距离,再减去x本身
            }
        }
    }

    2018-10-03

  • 相关阅读:
    Codeforces Round 731 (Div.3) 所有题目题解
    NOI2021 同步赛游记
    【题解】CF1547F Array Stabilization (GCD version)
    Codeforces 人类智慧题目大赏
    【题解】CF1559E Mocha and Stars
    OI 日常犯的一些错误
    AtCoder Beginner Contest(ABC) 247 A~G 题解
    【题解】[六省联考 2017] 组合数问题
    Something about My Blog
    【OI 退役记】NOIP2022 游记
  • 原文地址:https://www.cnblogs.com/00isok/p/9740775.html
Copyright © 2020-2023  润新知