「筆記」對頂堆動態維護中位數

Luckyblock發表於2024-04-26

目錄
  • 寫在前面
  • 問題
  • 思路
  • 程式碼
  • 例題
  • 寫在最後

寫在前面

媽的為啥我不會這個

問題

給定 \(n\) 次操作,要求動態地維護一個可重集合,每次操作為下列三種形式之一:

  • 給定引數 \(x\),向集合中插入一個權值 \(x\)
  • 給定引數 \(x\),刪除集合中已存在的一個權值 \(x\)
  • 查詢集合的中位數。

要求在 \(O(n\log n)\) 時間複雜度內實現。

思路

考慮對當前可重集合維護兩個 multiset,記它們分別為 \(A\)\(B\)\(A\) 中存小於等於中位數的權值,\(B\) 中存大於等於中位數的權值,且欽定 \(\operatorname{size}(A) \ge \operatorname{size}(B), \left|\operatorname{size}(A) - \operatorname{size}(B)\right|\le 1\)。則在此限制下 \(A\) 中最大的數即為集合的中位數。

考慮在上述限制下如何維護 \(A, B\)

  • 為了方便首先在 \(A\) 中插入極小值,\(B\) 中插入極大值。
  • 對於插入操作,若給定引數 \(x\le \operatorname{max}\{A\}\),則將 \(x\) 插入 \(A\),否則插入 \(B\)
  • 對於刪除操作,先查詢 \(A\) 中是否存在 \(x\),若存在則直接刪除,否則在 \(B\) 中查詢並刪除。
  • 每次插入刪除操作後,都進行調整操作:若 \(\operatorname{size}(A) > \operatorname{size}(B) + 1\) 則不斷取出 \(A\) 中最大值插入 \(B\);若 \(\operatorname{size}(B) > \operatorname{size}(A)\) 則不斷取出 \(B\) 中最小值插入 \(A\)
  • 完成調整後,查詢 \(A\) 中最大的數即為整個集合的中位數。

發現在上述過程中,單次調整至多僅會調整一個元素,則僅有常數次對 set 的操作。則單次插入/刪除時間複雜度 \(O(\log n)\) 級別,查詢 \(O(1)\) 級別。

注意 multiset.erase 時,若傳入的為值則會將所有值均刪除;傳入迭代器才僅會刪除一個。

程式碼

namespace Set {
  const int kInf = 1e9 + 2077;
  std::multiset<int> less, greater;
  void init() {
    less.clear(), greater.clear();
    less.insert(-kInf), greater.insert(kInf);
  }
  void adjust() {
    while (less.size() > greater.size() + 1) {
      std::multiset<int>::iterator it = (--less.end());
      greater.insert(*it);
      less.erase(it);
    }
    while (greater.size() > less.size()) {
      std::multiset<int>::iterator it = greater.begin();
      less.insert(*it);
      greater.erase(it);
    }
  }
  void add(int val_) {
    if (val_ <= *greater.begin()) less.insert(val_);
    else greater.insert(val_);
    adjust();
  }
  void del(int val_) {
    std::multiset<int>::iterator it = less.lower_bound(val_);
    if (it != less.end()) {
      less.erase(it);
    } else {
      it = greater.lower_bound(val_);
      greater.erase(it);
    }
    adjust();
  }
  int get_middle() {
    return *less.rbegin();
  }
}

例題

The 2023 ICPC Asia Jinan Regional Contest - K

寫在最後

媽的為啥我不會這個

相關文章