• poj 1988 Cube Stacking


    Cube Stacking

    题意:一个个数在30,000以内的盘子,编号从1开始,之后有K(K < 100,000)次操作;

    *M a b  In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
    *C a   In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.

    Sample Input

    6 (P)
    M 1 6
    C 1
    M 2 4
    M 2 6
    C 3
    C 4
    

    Sample Output

    1
    0
    2
    注:不会输入盘子的个数n,直接输入操作数P;(初始化)
    思路:f[]就可以容易的压缩出根节点,同时前面几题知道,对于一个子节点到根节点之间的关系可以通过路径压缩时建立在原父节点的基础之上;但是父节点不能得到子节点的信息;
    回归到本题,对于两个盘子集合的合并,按照上面,可以知道如果设数组num[i]表示盘子i下面盘子的个数,并且把最下面的盘子当成根节点,那么对于查询C a答案就是路径压缩之后的num[a];
    但是怎么合并呢?按照偏移向量的思想(先路径压缩,再由子节点得到被合并的根节点与最终根节点之间的关系,因为这样就可以把原根节点就是根节点的子节点,实现了两颗树的合并),那么在fu与fv之间就需要更新之间的关系,即f[fu] = fv时,需要得到合并之后fu下面有多少个盘子;
    这就需要知道根节点树有多少个节点;直接使用rk[]在合并的时候,更新一下根节点之间的关系(num[])即可;
    ps:要清楚在合并集合时需要合并的数据有什么?

    // 1064K    579MS
    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    const int MAXN = 30030;
    int f[MAXN];
    int num[MAXN],rk[MAXN];//num[i]:盘子i下面有多少个盘子,rk[]表示根节点所在树有多少个节点
    int Find(int a)//**
    {
        if(a == f[a]) return f[a];
        int fa = Find(f[a]);
        num[a] += num[f[a]];//加上没压缩之前的fa,此时num[f[a]]已经递推到了要fa的距离
        return f[a] = fa;
    }
    bool _union(int u,int v)
    {
        int fu = Find(u),fv = Find(v);
        f[fu] = fv;
        num[fu] = rk[fv];//**
        rk[fv] += rk[fu];
        return false;
    }
    int main()
    {
        int p,T,kase = 1;
        scanf("%d",&p);
        rep1(i,0,MAXN) rk[i] = 1,num[i] = 0,f[i]= i;
        rep0(i,0,p){
            char op[2];int a,b;
            scanf("%s",op);
            if(op[0] == 'M'){
                scanf("%d%d",&a,&b);
                _union(a,b);
            }
            else{
                scanf("%d",&a);
                Find(a);
                printf("%d
    ",num[a]);
            }
        }
        return 0;
    }
    View Code
    
    
    
  • 相关阅读:
    javascript之全局函数
    讲真,MySQL索引优化看这篇文章就够了
    aws亚马逊磁盘扩展卷步骤
    google支付回调验证(备用)
    Linux TCP状态TIME_WAIT 过多的处理
    MySQL索引优化分析
    CSS使图片变模糊,亲测非常好用
    linux ss 命令用法说明
    php一行代码获取本周一,本周日,上周一,上周日,本月一日,本月最后一日,上月一日,上月最后一日日期
    有哪些你追了很多女生才明白的道理?
  • 原文地址:https://www.cnblogs.com/hxer/p/5185540.html
Copyright © 2020-2023  润新知