【SJTUOJ笔记】P1056 二哥吃糖

https://acm.sjtu.edu.cn/OnlineJudge/problem/1056

    先看C操作。注意所有操作的参数都是糖果编号,但由于合并操作会将糖果打乱,所以我们需要设法快速找到特定编号的糖果在哪个盒子里。再加上C操作本身的合并,应该用并查集来实现这个功能。

    再看Q操作。Q操作询问糖果数量第p多的盒子中有多少糖果,并且指明了1<=p<=10,相对于N是一个很小的量级。因此,考虑采用大根堆来维护当前的糖果盒子。

    最后看D操作。同样,这个操作和并查集有关系。我们只需要把该集合最顶端的糖果标记为已吃掉,就可以用并查集的查询操作,在常数时间内查询到该集合内的任一糖果是否还存在。

    综上所述,这道题我采用堆+并查集来实现。其中,堆中只存储每个集合最顶端的元素,相当于存储了所有的糖果盒。

   核心部分如下:

// Node类型中的size表示该结点所在糖果盒中糖果的数目,但仅当该结点是根节点时才有效;ind表示在a中存储的下标。
// pos数组存储了每个结点在堆中的下标。

// 寻找第k大的函数。由于题目中所给的p(也就是k)非常小,采用删除k-1次堆顶、取得第k大、再把删除的元素重新放回的做法是不会超时的。这也是为何此题不需要更加复杂的数据结构。
int findk(int k){ 
    int tmp = Size;
    for (int i = 1; i <= k - 1; ++i){
        a[0] = a[1];
        a[1] = a[Size];
        a[Size] = a[0];
        pos[a[1].ind] = 1;
        pos[a[Size].ind] = Size;
        --Size;
        siftdown(1);
    }
    int ret = a[1].size;
    while (Size < tmp){
        ++Size;
        siftup(Size);
    }
    return ret;
}
//------------
    while (m--){
        char ch;
        int x, y;
        cin >> ch;
        switch(ch){
        case 'C':{
            cin >> x >> y;
            int px = getParent(x), py = getParent(y);
            if (!b[px] || !b[py] || px == py) break; // b存储该糖果盒内的糖果是否存在,用根结点表示
            p[px] = py;
            a[pos[py]].size += a[pos[px]].size;
            del(pos[px]);
            siftup(pos[py]);
            break;
        }
        case 'D':{
            cin >> x;
            int px = getParent(x);
            if (!b[px]) break;
            del(pos[px]);
            b[px] = false;
            break;
        }
        case 'Q':{
            cin >> x;
            if (Size < x)
                cout << "0\n";
            else
                cout << findk(x) << '\n';
            break;
        }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值