树状数组求第k小的元素

int find_kth(int k)
{
    int ans = 0,cnt = 0;
    for (int i = 20;i >= 0;i--)  //这里的20适当的取值,与MAX_VAL有关,一般取lg(MAX_VAL)
    {
        ans += (1 << i);
        if (ans >= maxn || cnt + c[ans] >= k)
            ans -= (1 << i);
        else
            cnt += c[ans];
    }
    return ans + 1
}

首先树状数组c[i]里面存的是在i管辖的范围内各个组数的和,比如 1出现2次,2出现3次,4出现6次,那么a[1]=2,a[2]=3,a[3]=0,a[4]=6;故c[4]=11;
所以总的元素如下{1,1,2,2,2,4,4,4,4,4,4}。知道了a[]数组的含义后(a[x]表示x出现的次数),我们再来看看树状数组求和的过程:
假设我们要求sum[15] (a[1] + …… + a[15]),根据树状数组巧妙的求和运算,依次累加c[1111(二进制表示)],c[1110],c[1100],c[1000]
反过来看,利用二进制,从高位到地位确定当前位是1还是0,首先假设是1,判断累计结果是否会超过k,超过K则假设不成立,应为0,继续确定下一位。基于二进制最后可以确定第k小的数的数值。(注意:利用树状数组求第k小的元素的时候是根据总的元素的,例如上面举例的{1,1,2,2,2,4,4,4,4,4,4},而不是在a[1],a[2],a[3],a[4]中去寻求第k小,并且求第k小时候包含重复元素的数数,没有直接跳过重复元素,例如还是上面的例子第2小还是1。

posted @   zxzhang  阅读(1129)  评论(1编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示