BIT在线求第k大数

在做小学期Day5C题在线维护中位数由于我没有做过也没有想到正解对顶堆卡了很久最后用一个奇怪的方法做出来了发现这个奇怪的做法复杂度稍高但是可以扩展对顶堆只能维护中位数或固定k的第k大数而奇怪做法可以在线查找第k大数k可变代价是$O(\log^2 n)$$n$为数列长度

步入正题

开始为空的一个数列有两种操作

  1. 向数列中加入一个元素a
  2. 输入k要求输出当前数列中第k大的数

首先加上一个限制数列中的元素a是1到n之间的整数且互不相同这一条其实无所谓联想用BIT求解逆序对的方法建立一棵权值BIT再二分答案查找不超过当前答案的数的个数目标是找到一个答案$ans$使得$sum(ans-1)<k$$sum(ans)\geq k$$sum$指BIT的求和操作代表不超过$ans$的数的个数每次获取个数的时间是$O(\log n)$共需要获取$O(\log n)$故复杂度为$O(\log^2 n)$

现在去掉限制允许$|A_i|\leq 10^{18}$为了沿用上面的办法需要将$A_i$映射到$[1,n]\cap\mathbb{N}$可以用unoerdered_mapgp_hash_table但这种映射需要提前将所有$A_i$读进来所以是在线到底算不算在线我也不知道

给个这道题的AC代码

AC代码

#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
map<int, int> num, arcnum;
int a[maxn], b[maxn], n;
int bit[maxn];
void add(int id, int x)
{
    while(id < maxn)
    {
        bit[id] += x;
        id += (id & -id);
    }
}
int sum(int id)
{
    int ret = 0;
    while(id > 0)
    {
        ret += bit[id];
        id -= (id & -id);
    }
    return ret;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int cnt = 1;
    for (int i = 1; i <= n; i++) {
        num[b[i]] = cnt;
        arcnum[cnt] = b[i];
        cnt++;
    }
    for (int i = 1; i <= n; i++) {
        add(num[a[i]], 1);
        if((i & 1) == 0)
            continue;
        int l = 0, r = maxn, mid = 0;
        while(l + 1 < r) {
            mid = (l + r) >> 1;
            if(sum(mid) < (i + 1) / 2) {//修改(i+1)/2即可询问第k大的数
                l = mid;
            } else {
                r = mid;
            }
        }
        cout << arcnum[r] << '\n';
    }
    return 0;
}