首页 > 其他分享 >对顶堆

对顶堆

时间:2024-10-09 17:22:20浏览次数:4  
标签: s2 s1 中位数 插入 text size

对顶堆

用于维护中位数。

维护两个 multiset,分别为 \(s1\) 与 \(s2\)。

\(s1\) 中存小于等于中位数的权值,\(s2\) 中存大于等于中位数的权值,且钦定 \(\text{size}(s1)≥\text{size}(s2),|\text{size}(s1)−\text{size}(s2)|≤1\)。

\(s1\) 中最大的数即为整个集合的中位数。

维护步骤:

  • 先在 \(s1\) 中插入极小值,\(s2\) 中插入极大值。
  • 对于插入操作,若 \(x\leq \text{max\{s1\}}\),则将 \(x\) 插入 \(s1\),否则插入 \(s2\)。
  • 对于删除操作,先查询 \(s1\) 中有无,再查询 \(s2\) 中有无。
  • 对于每次插入删除操作,都进行调整:若 \(\text{size}(s1)>\text{size}(s2) + 1\),则不断取出 \(s1\) 的最大值插入 \(s2\);若 \(\text{size}(s2)>\text{size}(s1)\),则不断取出 \(s2\) 的最小值插入 \(s1\)。
  • 调整完成后,\(s1\) 中最大的数即为集合的中位数。
multiset<int> s1;
multiset<int> s2;

void Init()
{
    s1.clear();
    s2.clear();
    s1.insert(-INF);
    s2.insert(INF);
}

void Change()
{
    while (s1.size() > s2.size() + 1)
    {
        ll x = *(--s1.end());
        s1.erase(--s1.end());
        s2.insert(x);
    }
    while (s2.size() > s1.size())
    {
        ll x = *s2.begin();
        s2.erase(s2.begin());
        s1.insert(x);
    }
}

void Insert(int x)
{
    if (x <= *s2.begin())
    {
        s1.insert(x);
    }
    else
    {
        s2.insert(x);
    }
    Change();
}

void Del(int x)
{
    auto it = s1.lower_bound(x);
    if (it != s1.end())
    {
        s1.erase(it);
    }
    else
    {
        it = s2.lower_bound(x);
        s2.erase(it);
    }
    Change();
}

int Zhong()
{
    return *s1.rbegin();
}

标签:,s2,s1,中位数,插入,text,size
From: https://www.cnblogs.com/EdisonBa/p/18454726

相关文章