专栏文章

题解:P11266 【模板】完全体·堆

P11266题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mir3h4ky
此快照首次捕获于
2025/12/04 15:08
3 个月前
此快照最后确认于
2025/12/04 15:08
3 个月前
查看原文
由于发现没人写平衡树,于是就有了这篇题解。

核心思路

不妨用 nn 棵平衡树 t1tnt_1\dots t_n 维护 nn 个集合,使用值作为键、出现次数作为值,那么各操作分别等同于:
  • 0 x y:如果 tx,ay=1t_{x,a_y}=1 则删除这一项,否则将其值减一。
  • 1 x:输出 txt_x 第一项的键。
  • 2 x y:枚举 tyt_y 的每一项 (k,v)(k,v),如果存在 tx,kt_{x,k} 则令 tx,ktx,k+vt_{x,k}\gets t_{x,k}+v,否则在 txt_x 中插入这一项,然后清空 tyt_y
  • 3 x y z:相当于先执行 0 x y,再将 aya_y 设为 zz,然后若存在 tx,zt_{x,z} 则将其值增加一,否则在 txt_x 中插入 (z,y)(z,y)
考虑使用 __gnu_pbds::treestd::map 维护可过。

参考代码

CPP
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;

int n, m, a[1000024];

tree<int, int> t[1000024];

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        t[i].insert({a[i], 1});
    }
    int tp, x, y, z;
    while (m--) {
        scanf("%d %d", &tp, &x);
        if (tp == 0) {
            scanf("%d", &y);
            if (t[x][a[y]] == 1) t[x].erase(a[y]);
            else t[x][a[y]]--;
        }
        else if (tp == 1) {
            printf("%d\n", t[x].begin()->first);
        }
        else if (tp == 2) {
            scanf("%d", &y);
            for (auto&[k, v] : t[y]) {
                auto it = t[x].find(k);
                if (it != t[x].end()) it->second += v;
                else t[x].insert({k, v});
            }
            t[y].clear();
        }
        else if (tp == 3) {
            scanf("%d %d", &y, &z);
            if (t[x][a[y]] == 1) t[x].erase(a[y]);
            else t[x][a[y]]--;
            a[y] = z;
            auto it = t[x].find(z);
            if (it != t[x].end()) it->second++;
            else t[x].insert({z, 1});
        }
    }
    return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...