可删除堆

定义:

也是属于对朴素堆的一种应用

一个不同于 朴素堆只可以删除堆顶的 可删除堆,它可任意元素进行删除。

为了保证可以 任意删除 元素,可删除堆是通过

构建两个堆,一个堆维护存放在堆中的元素,另一个堆维护应该被删除的元素。

为了方便称呼,我们称 维护存放在堆中的元素的堆 为原堆,堆维护应该被删除的元素的堆 为删堆。

原理呢,因为在使用堆的过程中,往往是去一个集合的最大值和最小值,然鹅要删除的元素对当前的最大值(或最小值)并无影响。由于 朴素堆 只能满足删除堆顶元素,那么只有当 应该已删除的元素 位于堆顶的时候,才会影响答案。那就先把 删除的元素 放入另一个相似的堆里,作为标记。

当 原堆的堆顶 为 要删的元素 时, 另一个堆的堆顶也一定是这个元素,那么就可以愉快地删掉啦!

操作:

  • #插入Insert:

将要插入的元素push进原堆里,即

void insert(int x) {q1.push(x); }
  • #删除Delete:

将要删除的元素push进删堆里,而不动 原堆 即

void del(int x) {q2.push(x);}
  • #查询get:

假设我们要得到 某些数的最大值,即大根堆。

我们要在原堆中 取出堆顶元素,但是可能这个堆顶元素已经被删除了,也就是入了删堆。
此时可以想到,原堆的最大值和删堆的最大值一定都是堆顶,且相同。
所以我们开始pop两个堆,也就是真真正正的删掉了这个元素

int get() {
    while(!q2.empty()&&!q1.empty()&&q2.top()==q1.top())
        q1.pop(), q2.pop();
    return q1.top();
}

代码

【可删除堆のCode】
struct Heap {// 可删除堆
    priority_queue<ll, vector<ll>, greater<ll> > q1, q2;
    // q1 维护存放在堆中的元素的堆,即原堆 
    // q2 维护应该被删除的元素的堆,即删堆。
    void insert(int x) {
    //插入Insert:将要插入的元素push进原堆里
	q1.push(x);
    }
    void del(int x) {
    //删除Delete:将要删除的元素push进删堆里,而不动 原堆
	q2.push(x);
    }
    int get() {//查询get
	while(!q2.empty()&&!q1.empty()&&q2.top()==q1.top()) {
	    q1.pop(), q2.pop();
	}
	return q1.top();
    }
} heap;
posted @ 2022-08-09 10:57  Ciaxin  阅读(485)  评论(2编辑  收藏  举报